Fix stale pending keybinding indicators on focus change (#44678)

Xipeng Jin , Nathan Sobo , and Conrad Irwin created

Closes #ISSUE

Problem:

- The status bar’s pending keystroke indicator (shown next to --NORMAL--
in Vim mode) didn’t clear when focus moved to another context, e.g.
hitting g in the editor then clicking the Git panel. The keymap state
correctly canceled the prefix, but observers that render the indicator
never received a β€œpending input changed” notification, so the UI kept
showing stale prefixes until a new keystroke occurred.

Fix:

- The change introduces a `pending_input_changed_queued` flag and a new
helper `notify_pending_input_if_needed` which will flushes the queued
notification as soon as we have an App context. The
`pending_input_changed` now resets the flag after notifying subscribers.

Before:


https://github.com/user-attachments/assets/7bec4c34-acbf-42bd-b0d1-88df5ff099aa

After:



https://github.com/user-attachments/assets/2264dc93-3405-4d63-ad8f-50ada6733ae7



Release Notes:

- Fixed: pending keybinding prefixes on the status bar now clear
immediately when focus moves to another panel or UI context.

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/agent_ui/src/acp/message_editor.rs                                 |   6 
crates/agent_ui/src/acp/thread_view.rs                                    |  14 
crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs         |  10 
crates/agent_ui/src/agent_configuration/configure_context_server_modal.rs |   2 
crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs          |  16 
crates/agent_ui/src/agent_diff.rs                                         |   8 
crates/agent_ui/src/agent_panel.rs                                        |  16 
crates/agent_ui/src/inline_assistant.rs                                   |   4 
crates/agent_ui/src/inline_prompt_editor.rs                               |   2 
crates/agent_ui/src/terminal_inline_assistant.rs                          |   6 
crates/agent_ui/src/text_thread_editor.rs                                 |   2 
crates/agent_ui/src/ui/acp_onboarding_modal.rs                            |   4 
crates/agent_ui/src/ui/claude_code_onboarding_modal.rs                    |   4 
crates/agent_ui/src/ui/onboarding_modal.rs                                |   4 
crates/collab_ui/src/collab_panel.rs                                      |  16 
crates/collab_ui/src/collab_panel/channel_modal.rs                        |   2 
crates/command_palette/src/command_palette.rs                             |   6 
crates/copilot/src/copilot_edit_prediction_delegate.rs                    |   4 
crates/copilot/src/sign_in.rs                                             |   4 
crates/debugger_ui/src/debugger_panel.rs                                  |   4 
crates/debugger_ui/src/new_process_modal.rs                               |  22 
crates/debugger_ui/src/onboarding_modal.rs                                |   4 
crates/debugger_ui/src/session/running.rs                                 |   2 
crates/debugger_ui/src/session/running/breakpoint_list.rs                 |  10 
crates/debugger_ui/src/session/running/console.rs                         |   2 
crates/debugger_ui/src/session/running/memory_view.rs                     |   2 
crates/debugger_ui/src/session/running/variable_list.rs                   |   4 
crates/diagnostics/src/buffer_diagnostics.rs                              |   6 
crates/diagnostics/src/diagnostic_renderer.rs                             |   2 
crates/diagnostics/src/diagnostics.rs                                     |   6 
crates/edit_prediction/src/onboarding_modal.rs                            |   4 
crates/edit_prediction_ui/src/rate_prediction_modal.rs                    |   2 
crates/editor/benches/editor_render.rs                                    |   6 
crates/editor/src/editor.rs                                               |  20 
crates/editor/src/editor_tests.rs                                         |   2 
crates/editor/src/hover_links.rs                                          |   2 
crates/editor/src/mouse_context_menu.rs                                   |  10 
crates/editor/src/test/editor_lsp_test_context.rs                         |   2 
crates/editor/src/test/editor_test_context.rs                             |   4 
crates/file_finder/src/file_finder.rs                                     |   2 
crates/git_ui/src/branch_picker.rs                                        |   6 
crates/git_ui/src/commit_modal.rs                                         |   6 
crates/git_ui/src/file_history_view.rs                                    |   4 
crates/git_ui/src/git_panel.rs                                            |  18 
crates/git_ui/src/git_ui.rs                                               |   2 
crates/git_ui/src/onboarding.rs                                           |   4 
crates/git_ui/src/project_diff.rs                                         |  10 
crates/go_to_line/src/go_to_line.rs                                       |   2 
crates/gpui/examples/focus_visible.rs                                     |  10 
crates/gpui/examples/input.rs                                             |   2 
crates/gpui/examples/on_window_close_quit.rs                              |   4 
crates/gpui/examples/tab_stop.rs                                          |  10 
crates/gpui/src/app.rs                                                    |   7 
crates/gpui/src/app/async_context.rs                                      |   2 
crates/gpui/src/app/context.rs                                            |   4 
crates/gpui/src/app/test_context.rs                                       |   2 
crates/gpui/src/elements/div.rs                                           |   6 
crates/gpui/src/elements/uniform_list.rs                                  |   2 
crates/gpui/src/interactive.rs                                            |   4 
crates/gpui/src/key_dispatch.rs                                           | 218 
crates/gpui/src/window.rs                                                 |  28 
crates/gpui/src/window/prompts.rs                                         |   6 
crates/gpui_macros/src/derive_visual_context.rs                           |   2 
crates/keymap_editor/src/keymap_editor.rs                                 |  28 
crates/keymap_editor/src/ui_components/keystroke_input.rs                 |   4 
crates/language_models/src/provider/bedrock.rs                            |   8 
crates/language_tools/src/lsp_log_view.rs                                 |  14 
crates/language_tools/src/syntax_tree_view.rs                             |   2 
crates/markdown/src/markdown.rs                                           |   2 
crates/markdown_preview/src/markdown_preview_view.rs                      |   4 
crates/onboarding/src/onboarding.rs                                       |   6 
crates/outline/src/outline.rs                                             |   2 
crates/outline_panel/src/outline_panel.rs                                 |  12 
crates/picker/src/picker.rs                                               |   2 
crates/project_panel/src/project_panel.rs                                 |  18 
crates/recent_projects/src/remote_connections.rs                          |   2 
crates/recent_projects/src/remote_servers.rs                              |  24 
crates/rules_library/src/rules_library.rs                                 |  14 
crates/search/src/buffer_search.rs                                        |  26 
crates/search/src/project_search.rs                                       |  16 
crates/search/src/search.rs                                               |   2 
crates/search/src/search_bar.rs                                           |   2 
crates/settings_ui/src/settings_ui.rs                                     |  53 
crates/terminal_view/src/terminal_element.rs                              |   4 
crates/terminal_view/src/terminal_panel.rs                                |  20 
crates/terminal_view/src/terminal_view.rs                                 |   2 
crates/title_bar/src/title_bar.rs                                         |   2 
crates/toolchain_selector/src/toolchain_selector.rs                       |  10 
crates/ui/src/components/context_menu.rs                                  |   4 
crates/ui/src/components/navigable.rs                                     |   4 
crates/ui/src/components/popover_menu.rs                                  |   6 
crates/ui/src/components/right_click_menu.rs                              |   6 
crates/ui_input/src/number_field.rs                                       |   4 
crates/workspace/src/dock.rs                                              |   8 
crates/workspace/src/item.rs                                              |   2 
crates/workspace/src/modal_layer.rs                                       |   4 
crates/workspace/src/pane.rs                                              |  10 
crates/workspace/src/welcome.rs                                           |   4 
crates/workspace/src/workspace.rs                                         |  40 
crates/zed/src/main.rs                                                    |   2 
crates/zed/src/zed.rs                                                     |   2 
crates/zed/src/zed/component_preview.rs                                   |   4 
102 files changed, 606 insertions(+), 380 deletions(-)

Detailed changes

crates/agent_ui/src/acp/message_editor.rs πŸ”—

@@ -1365,7 +1365,7 @@ mod tests {
                     cx,
                 );
             });
-            message_editor.read(cx).focus_handle(cx).focus(window);
+            message_editor.read(cx).focus_handle(cx).focus(window, cx);
             message_editor.read(cx).editor().clone()
         });
 
@@ -1587,7 +1587,7 @@ mod tests {
                     cx,
                 );
             });
-            message_editor.read(cx).focus_handle(cx).focus(window);
+            message_editor.read(cx).focus_handle(cx).focus(window, cx);
             let editor = message_editor.read(cx).editor().clone();
             (message_editor, editor)
         });
@@ -2315,7 +2315,7 @@ mod tests {
                     cx,
                 );
             });
-            message_editor.read(cx).focus_handle(cx).focus(window);
+            message_editor.read(cx).focus_handle(cx).focus(window, cx);
             let editor = message_editor.read(cx).editor().clone();
             (message_editor, editor)
         });

crates/agent_ui/src/acp/thread_view.rs πŸ”—

@@ -253,7 +253,7 @@ impl ThreadFeedbackState {
             editor
         });
 
-        editor.read(cx).focus_handle(cx).focus(window);
+        editor.read(cx).focus_handle(cx).focus(window, cx);
         editor
     }
 }
@@ -682,7 +682,7 @@ impl AcpThreadView {
                             })
                         });
 
-                        this.message_editor.focus_handle(cx).focus(window);
+                        this.message_editor.focus_handle(cx).focus(window, cx);
 
                         cx.notify();
                     }
@@ -784,7 +784,7 @@ impl AcpThreadView {
                 _subscription: subscription,
             };
             if this.message_editor.focus_handle(cx).is_focused(window) {
-                this.focus_handle.focus(window)
+                this.focus_handle.focus(window, cx)
             }
             cx.notify();
         })
@@ -804,7 +804,7 @@ impl AcpThreadView {
                 ThreadState::LoadError(LoadError::Other(format!("{:#}", err).into()))
         }
         if self.message_editor.focus_handle(cx).is_focused(window) {
-            self.focus_handle.focus(window)
+            self.focus_handle.focus(window, cx)
         }
         cx.notify();
     }
@@ -1270,7 +1270,7 @@ impl AcpThreadView {
                 }
             })
         };
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
         cx.notify();
     }
 
@@ -1322,7 +1322,7 @@ impl AcpThreadView {
                 .await?;
             this.update_in(cx, |this, window, cx| {
                 this.send_impl(message_editor, window, cx);
-                this.focus_handle(cx).focus(window);
+                this.focus_handle(cx).focus(window, cx);
             })?;
             anyhow::Ok(())
         })
@@ -1465,7 +1465,7 @@ impl AcpThreadView {
                 self.thread_retry_status.take();
                 self.thread_state = ThreadState::LoadError(error.clone());
                 if self.message_editor.focus_handle(cx).is_focused(window) {
-                    self.focus_handle.focus(window)
+                    self.focus_handle.focus(window, cx)
                 }
             }
             AcpThreadEvent::TitleUpdated => {

crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs πŸ”—

@@ -446,17 +446,17 @@ impl AddLlmProviderModal {
             })
     }
 
-    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_next();
+    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_next(cx);
     }
 
     fn on_tab_prev(
         &mut self,
         _: &menu::SelectPrevious,
         window: &mut Window,
-        _: &mut Context<Self>,
+        cx: &mut Context<Self>,
     ) {
-        window.focus_prev();
+        window.focus_prev(cx);
     }
 }
 
@@ -493,7 +493,7 @@ impl Render for AddLlmProviderModal {
             .on_action(cx.listener(Self::on_tab))
             .on_action(cx.listener(Self::on_tab_prev))
             .capture_any_mouse_down(cx.listener(|this, _, window, cx| {
-                this.focus_handle(cx).focus(window);
+                this.focus_handle(cx).focus(window, cx);
             }))
             .child(
                 Modal::new("configure-context-server", None)

crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs πŸ”—

@@ -156,7 +156,7 @@ impl ManageProfilesModal {
             cx.observe_global_in::<SettingsStore>(window, |this, window, cx| {
                 if matches!(this.mode, Mode::ChooseProfile(_)) {
                     this.mode = Mode::choose_profile(window, cx);
-                    this.focus_handle(cx).focus(window);
+                    this.focus_handle(cx).focus(window, cx);
                     cx.notify();
                 }
             });
@@ -173,7 +173,7 @@ impl ManageProfilesModal {
 
     fn choose_profile(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.mode = Mode::choose_profile(window, cx);
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     fn new_profile(
@@ -191,7 +191,7 @@ impl ManageProfilesModal {
             name_editor,
             base_profile_id,
         });
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     pub fn view_profile(
@@ -209,7 +209,7 @@ impl ManageProfilesModal {
             delete_profile: NavigableEntry::focusable(cx),
             cancel_item: NavigableEntry::focusable(cx),
         });
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     fn configure_default_model(
@@ -300,7 +300,7 @@ impl ManageProfilesModal {
             model_picker,
             _subscription: dismiss_subscription,
         };
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     fn configure_mcp_tools(
@@ -336,7 +336,7 @@ impl ManageProfilesModal {
             tool_picker,
             _subscription: dismiss_subscription,
         };
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     fn configure_builtin_tools(
@@ -377,7 +377,7 @@ impl ManageProfilesModal {
             tool_picker,
             _subscription: dismiss_subscription,
         };
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     fn confirm(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -951,7 +951,7 @@ impl Render for ManageProfilesModal {
             .on_action(cx.listener(|this, _: &menu::Cancel, window, cx| this.cancel(window, cx)))
             .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| this.confirm(window, cx)))
             .capture_any_mouse_down(cx.listener(|this, _, window, cx| {
-                this.focus_handle(cx).focus(window);
+                this.focus_handle(cx).focus(window, cx);
             }))
             .on_mouse_down_out(cx.listener(|_this, _, _, cx| cx.emit(DismissEvent)))
             .child(match &self.mode {

crates/agent_ui/src/agent_diff.rs πŸ”—

@@ -212,10 +212,10 @@ impl AgentDiffPane {
                 .focus_handle(cx)
                 .contains_focused(window, cx)
         {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         } else if self.focus_handle.is_focused(window) && !self.multibuffer.read(cx).is_empty() {
             self.editor.update(cx, |editor, cx| {
-                editor.focus_handle(cx).focus(window);
+                editor.focus_handle(cx).focus(window, cx);
             });
         }
     }
@@ -874,12 +874,12 @@ impl AgentDiffToolbar {
         match active_item {
             AgentDiffToolbarItem::Pane(agent_diff) => {
                 if let Some(agent_diff) = agent_diff.upgrade() {
-                    agent_diff.focus_handle(cx).focus(window);
+                    agent_diff.focus_handle(cx).focus(window, cx);
                 }
             }
             AgentDiffToolbarItem::Editor { editor, .. } => {
                 if let Some(editor) = editor.upgrade() {
-                    editor.read(cx).focus_handle(cx).focus(window);
+                    editor.read(cx).focus_handle(cx).focus(window, cx);
                 }
             }
         }

crates/agent_ui/src/agent_panel.rs πŸ”—

@@ -880,7 +880,7 @@ impl AgentPanel {
             window,
             cx,
         );
-        text_thread_editor.focus_handle(cx).focus(window);
+        text_thread_editor.focus_handle(cx).focus(window, cx);
     }
 
     fn external_thread(
@@ -1034,7 +1034,7 @@ impl AgentPanel {
         if let Some(thread_view) = self.active_thread_view() {
             thread_view.update(cx, |view, cx| {
                 view.expand_message_editor(&ExpandMessageEditor, window, cx);
-                view.focus_handle(cx).focus(window);
+                view.focus_handle(cx).focus(window, cx);
             });
         }
     }
@@ -1115,12 +1115,12 @@ impl AgentPanel {
 
                     match &self.active_view {
                         ActiveView::ExternalAgentThread { thread_view } => {
-                            thread_view.focus_handle(cx).focus(window);
+                            thread_view.focus_handle(cx).focus(window, cx);
                         }
                         ActiveView::TextThread {
                             text_thread_editor, ..
                         } => {
-                            text_thread_editor.focus_handle(cx).focus(window);
+                            text_thread_editor.focus_handle(cx).focus(window, cx);
                         }
                         ActiveView::History | ActiveView::Configuration => {}
                     }
@@ -1268,7 +1268,7 @@ impl AgentPanel {
                 Self::handle_agent_configuration_event,
             ));
 
-            configuration.focus_handle(cx).focus(window);
+            configuration.focus_handle(cx).focus(window, cx);
         }
     }
 
@@ -1404,7 +1404,7 @@ impl AgentPanel {
         }
 
         if focus {
-            self.focus_handle(cx).focus(window);
+            self.focus_handle(cx).focus(window, cx);
         }
     }
 
@@ -1761,7 +1761,7 @@ impl AgentPanel {
                             let thread_view = thread_view.downgrade();
                             move |_: &menu::Confirm, window, cx| {
                                 if let Some(thread_view) = thread_view.upgrade() {
-                                    thread_view.focus_handle(cx).focus(window);
+                                    thread_view.focus_handle(cx).focus(window, cx);
                                 }
                             }
                         })
@@ -1769,7 +1769,7 @@ impl AgentPanel {
                             let thread_view = thread_view.downgrade();
                             move |_: &editor::actions::Cancel, window, cx| {
                                 if let Some(thread_view) = thread_view.upgrade() {
-                                    thread_view.focus_handle(cx).focus(window);
+                                    thread_view.focus_handle(cx).focus(window, cx);
                                 }
                             }
                         })

crates/agent_ui/src/inline_assistant.rs πŸ”—

@@ -1197,7 +1197,7 @@ impl InlineAssistant {
 
         assist
             .editor
-            .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx)))
+            .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx), cx))
             .ok();
     }
 
@@ -1209,7 +1209,7 @@ impl InlineAssistant {
         if let Some(decorations) = assist.decorations.as_ref() {
             decorations.prompt_editor.update(cx, |prompt_editor, cx| {
                 prompt_editor.editor.update(cx, |editor, cx| {
-                    window.focus(&editor.focus_handle(cx));
+                    window.focus(&editor.focus_handle(cx), cx);
                     editor.select_all(&SelectAll, window, cx);
                 })
             });

crates/agent_ui/src/inline_prompt_editor.rs πŸ”—

@@ -357,7 +357,7 @@ impl<T: 'static> PromptEditor<T> {
             creases = insert_message_creases(&mut editor, &existing_creases, window, cx);
 
             if focus {
-                window.focus(&editor.focus_handle(cx));
+                window.focus(&editor.focus_handle(cx), cx);
             }
             editor
         });

crates/agent_ui/src/terminal_inline_assistant.rs πŸ”—

@@ -127,7 +127,7 @@ impl TerminalInlineAssistant {
         if let Some(prompt_editor) = assist.prompt_editor.as_ref() {
             prompt_editor.update(cx, |this, cx| {
                 this.editor.update(cx, |editor, cx| {
-                    window.focus(&editor.focus_handle(cx));
+                    window.focus(&editor.focus_handle(cx), cx);
                     editor.select_all(&SelectAll, window, cx);
                 });
             });
@@ -292,7 +292,7 @@ impl TerminalInlineAssistant {
                 .terminal
                 .update(cx, |this, cx| {
                     this.clear_block_below_cursor(cx);
-                    this.focus_handle(cx).focus(window);
+                    this.focus_handle(cx).focus(window, cx);
                 })
                 .log_err();
 
@@ -369,7 +369,7 @@ impl TerminalInlineAssistant {
             .terminal
             .update(cx, |this, cx| {
                 this.clear_block_below_cursor(cx);
-                this.focus_handle(cx).focus(window);
+                this.focus_handle(cx).focus(window, cx);
             })
             .is_ok()
     }

crates/agent_ui/src/text_thread_editor.rs πŸ”—

@@ -1341,7 +1341,7 @@ impl TextThreadEditor {
         if let Some((text, _)) = Self::get_selection_or_code_block(&context_editor_view, cx) {
             active_editor_view.update(cx, |editor, cx| {
                 editor.insert(&text, window, cx);
-                editor.focus_handle(cx).focus(window);
+                editor.focus_handle(cx).focus(window, cx);
             })
         }
     }

crates/agent_ui/src/ui/acp_onboarding_modal.rs πŸ”—

@@ -222,8 +222,8 @@ impl Render for AcpOnboardingModal {
                 acp_onboarding_event!("Canceled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(illustration)
             .child(

crates/agent_ui/src/ui/claude_code_onboarding_modal.rs πŸ”—

@@ -230,8 +230,8 @@ impl Render for ClaudeCodeOnboardingModal {
                 claude_code_onboarding_event!("Canceled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(illustration)
             .child(

crates/agent_ui/src/ui/onboarding_modal.rs πŸ”—

@@ -83,8 +83,8 @@ impl Render for AgentOnboardingModal {
                 agent_onboarding_event!("Canceled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(
                 div()

crates/collab_ui/src/collab_panel.rs πŸ”—

@@ -1252,7 +1252,7 @@ impl CollabPanel {
             context_menu
         });
 
-        window.focus(&context_menu.focus_handle(cx));
+        window.focus(&context_menu.focus_handle(cx), cx);
         let subscription = cx.subscribe_in(
             &context_menu,
             window,
@@ -1424,7 +1424,7 @@ impl CollabPanel {
             context_menu
         });
 
-        window.focus(&context_menu.focus_handle(cx));
+        window.focus(&context_menu.focus_handle(cx), cx);
         let subscription = cx.subscribe_in(
             &context_menu,
             window,
@@ -1487,7 +1487,7 @@ impl CollabPanel {
             })
         });
 
-        window.focus(&context_menu.focus_handle(cx));
+        window.focus(&context_menu.focus_handle(cx), cx);
         let subscription = cx.subscribe_in(
             &context_menu,
             window,
@@ -1521,9 +1521,9 @@ impl CollabPanel {
         if cx.stop_active_drag(window) {
             return;
         } else if self.take_editing_state(window, cx) {
-            window.focus(&self.filter_editor.focus_handle(cx));
+            window.focus(&self.filter_editor.focus_handle(cx), cx);
         } else if !self.reset_filter_editor_text(window, cx) {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         }
 
         if self.context_menu.is_some() {
@@ -1826,7 +1826,7 @@ impl CollabPanel {
         });
         self.update_entries(false, cx);
         self.select_channel_editor();
-        window.focus(&self.channel_name_editor.focus_handle(cx));
+        window.focus(&self.channel_name_editor.focus_handle(cx), cx);
         cx.notify();
     }
 
@@ -1851,7 +1851,7 @@ impl CollabPanel {
         });
         self.update_entries(false, cx);
         self.select_channel_editor();
-        window.focus(&self.channel_name_editor.focus_handle(cx));
+        window.focus(&self.channel_name_editor.focus_handle(cx), cx);
         cx.notify();
     }
 
@@ -1900,7 +1900,7 @@ impl CollabPanel {
                 editor.set_text(channel.name.clone(), window, cx);
                 editor.select_all(&Default::default(), window, cx);
             });
-            window.focus(&self.channel_name_editor.focus_handle(cx));
+            window.focus(&self.channel_name_editor.focus_handle(cx), cx);
             self.update_entries(false, cx);
             self.select_channel_editor();
         }

crates/command_palette/src/command_palette.rs πŸ”—

@@ -588,7 +588,7 @@ impl PickerDelegate for CommandPaletteDelegate {
         })
         .detach_and_log_err(cx);
         let action = command.action;
-        window.focus(&self.previous_focus_handle);
+        window.focus(&self.previous_focus_handle, cx);
         self.dismissed(window, cx);
         window.dispatch_action(action, cx);
     }
@@ -784,7 +784,7 @@ mod tests {
 
         workspace.update_in(cx, |workspace, window, cx| {
             workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
-            editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx)))
+            editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx), cx))
         });
 
         cx.simulate_keystrokes("cmd-shift-p");
@@ -855,7 +855,7 @@ mod tests {
 
         workspace.update_in(cx, |workspace, window, cx| {
             workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
-            editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx)))
+            editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx), cx))
         });
 
         // Test normalize (trimming whitespace and double colons)

crates/copilot/src/copilot_edit_prediction_delegate.rs πŸ”—

@@ -753,7 +753,7 @@ mod tests {
         editor
             .update(cx, |editor, window, cx| {
                 use gpui::Focusable;
-                window.focus(&editor.focus_handle(cx));
+                window.focus(&editor.focus_handle(cx), cx);
             })
             .unwrap();
         let copilot_provider = cx.new(|_| CopilotEditPredictionDelegate::new(copilot));
@@ -1000,7 +1000,7 @@ mod tests {
         editor
             .update(cx, |editor, window, cx| {
                 use gpui::Focusable;
-                window.focus(&editor.focus_handle(cx))
+                window.focus(&editor.focus_handle(cx), cx)
             })
             .unwrap();
         let copilot_provider = cx.new(|_| CopilotEditPredictionDelegate::new(copilot));

crates/copilot/src/sign_in.rs πŸ”—

@@ -435,8 +435,8 @@ impl Render for CopilotCodeVerification {
             .on_action(cx.listener(|_, _: &menu::Cancel, _, cx| {
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _| {
-                window.focus(&this.focus_handle);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                window.focus(&this.focus_handle, cx);
             }))
             .child(
                 Vector::new(VectorName::ZedXCopilot, rems(8.), rems(4.))

crates/debugger_ui/src/debugger_panel.rs πŸ”—

@@ -577,7 +577,7 @@ impl DebugPanel {
                 menu
             });
 
-            window.focus(&context_menu.focus_handle(cx));
+            window.focus(&context_menu.focus_handle(cx), cx);
             let subscription = cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
                 this.context_menu.take();
                 cx.notify();
@@ -1052,7 +1052,7 @@ impl DebugPanel {
         cx: &mut Context<Self>,
     ) {
         debug_assert!(self.sessions_with_children.contains_key(&session_item));
-        session_item.focus_handle(cx).focus(window);
+        session_item.focus_handle(cx).focus(window, cx);
         session_item.update(cx, |this, cx| {
             this.running_state().update(cx, |this, cx| {
                 this.go_to_selected_stack_frame(window, cx);

crates/debugger_ui/src/new_process_modal.rs πŸ”—

@@ -574,7 +574,7 @@ impl Render for NewProcessModal {
                     NewProcessMode::Launch => NewProcessMode::Task,
                 };
 
-                this.mode_focus_handle(cx).focus(window);
+                this.mode_focus_handle(cx).focus(window, cx);
             }))
             .on_action(
                 cx.listener(|this, _: &pane::ActivatePreviousItem, window, cx| {
@@ -585,7 +585,7 @@ impl Render for NewProcessModal {
                         NewProcessMode::Launch => NewProcessMode::Attach,
                     };
 
-                    this.mode_focus_handle(cx).focus(window);
+                    this.mode_focus_handle(cx).focus(window, cx);
                 }),
             )
             .child(
@@ -602,7 +602,7 @@ impl Render for NewProcessModal {
                                     NewProcessMode::Task.to_string(),
                                     cx.listener(|this, _, window, cx| {
                                         this.mode = NewProcessMode::Task;
-                                        this.mode_focus_handle(cx).focus(window);
+                                        this.mode_focus_handle(cx).focus(window, cx);
                                         cx.notify();
                                     }),
                                 )
@@ -611,7 +611,7 @@ impl Render for NewProcessModal {
                                     NewProcessMode::Debug.to_string(),
                                     cx.listener(|this, _, window, cx| {
                                         this.mode = NewProcessMode::Debug;
-                                        this.mode_focus_handle(cx).focus(window);
+                                        this.mode_focus_handle(cx).focus(window, cx);
                                         cx.notify();
                                     }),
                                 )
@@ -629,7 +629,7 @@ impl Render for NewProcessModal {
                                                 cx,
                                             );
                                         }
-                                        this.mode_focus_handle(cx).focus(window);
+                                        this.mode_focus_handle(cx).focus(window, cx);
                                         cx.notify();
                                     }),
                                 )
@@ -638,7 +638,7 @@ impl Render for NewProcessModal {
                                     NewProcessMode::Launch.to_string(),
                                     cx.listener(|this, _, window, cx| {
                                         this.mode = NewProcessMode::Launch;
-                                        this.mode_focus_handle(cx).focus(window);
+                                        this.mode_focus_handle(cx).focus(window, cx);
                                         cx.notify();
                                     }),
                                 )
@@ -840,17 +840,17 @@ impl ConfigureMode {
         }
     }
 
-    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_next();
+    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_next(cx);
     }
 
     fn on_tab_prev(
         &mut self,
         _: &menu::SelectPrevious,
         window: &mut Window,
-        _: &mut Context<Self>,
+        cx: &mut Context<Self>,
     ) {
-        window.focus_prev();
+        window.focus_prev(cx);
     }
 
     fn render(
@@ -923,7 +923,7 @@ impl AttachMode {
                 window,
                 cx,
             );
-            window.focus(&modal.focus_handle(cx));
+            window.focus(&modal.focus_handle(cx), cx);
 
             modal
         });

crates/debugger_ui/src/onboarding_modal.rs πŸ”—

@@ -83,8 +83,8 @@ impl Render for DebuggerOnboardingModal {
                 debugger_onboarding_event!("Canceled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(
                 div()

crates/debugger_ui/src/session/running.rs πŸ”—

@@ -604,7 +604,7 @@ impl DebugTerminal {
         let focus_handle = cx.focus_handle();
         let focus_subscription = cx.on_focus(&focus_handle, window, |this, window, cx| {
             if let Some(terminal) = this.terminal.as_ref() {
-                terminal.focus_handle(cx).focus(window);
+                terminal.focus_handle(cx).focus(window, cx);
             }
         });
 

crates/debugger_ui/src/session/running/breakpoint_list.rs πŸ”—

@@ -310,7 +310,7 @@ impl BreakpointList {
 
     fn dismiss(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
         if self.input.focus_handle(cx).contains_focused(window, cx) {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         } else if self.strip_mode.is_some() {
             self.strip_mode.take();
             cx.notify();
@@ -364,9 +364,9 @@ impl BreakpointList {
                         }
                     }
                 }
-                self.focus_handle.focus(window);
+                self.focus_handle.focus(window, cx);
             } else {
-                handle.focus(window);
+                handle.focus(window, cx);
             }
 
             return;
@@ -627,7 +627,7 @@ impl BreakpointList {
                 .on_click({
                     let focus_handle = focus_handle.clone();
                     move |_, window, cx| {
-                        focus_handle.focus(window);
+                        focus_handle.focus(window, cx);
                         window.dispatch_action(ToggleEnableBreakpoint.boxed_clone(), cx)
                     }
                 }),
@@ -654,7 +654,7 @@ impl BreakpointList {
                     )
                     .on_click({
                         move |_, window, cx| {
-                            focus_handle.focus(window);
+                            focus_handle.focus(window, cx);
                             window.dispatch_action(UnsetBreakpoint.boxed_clone(), cx)
                         }
                     }),

crates/debugger_ui/src/session/running/console.rs πŸ”—

@@ -105,7 +105,7 @@ impl Console {
             cx.subscribe(&stack_frame_list, Self::handle_stack_frame_list_events),
             cx.on_focus(&focus_handle, window, |console, window, cx| {
                 if console.is_running(cx) {
-                    console.query_bar.focus_handle(cx).focus(window);
+                    console.query_bar.focus_handle(cx).focus(window, cx);
                 }
             }),
         ];

crates/debugger_ui/src/session/running/memory_view.rs πŸ”—

@@ -403,7 +403,7 @@ impl MemoryView {
                 this.set_placeholder_text("Write to Selected Memory Range", window, cx);
             });
             self.is_writing_memory = true;
-            self.query_editor.focus_handle(cx).focus(window);
+            self.query_editor.focus_handle(cx).focus(window, cx);
         } else {
             self.query_editor.update(cx, |this, cx| {
                 this.clear(window, cx);

crates/debugger_ui/src/session/running/variable_list.rs πŸ”—

@@ -529,7 +529,7 @@ impl VariableList {
 
     fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
         self.edited_path.take();
-        self.focus_handle.focus(window);
+        self.focus_handle.focus(window, cx);
         cx.notify();
     }
 
@@ -1067,7 +1067,7 @@ impl VariableList {
             editor.select_all(&editor::actions::SelectAll, window, cx);
             editor
         });
-        editor.focus_handle(cx).focus(window);
+        editor.focus_handle(cx).focus(window, cx);
         editor
     }
 

crates/diagnostics/src/buffer_diagnostics.rs πŸ”—

@@ -175,7 +175,7 @@ impl BufferDiagnosticsEditor {
                     // `BufferDiagnosticsEditor` instance.
                     EditorEvent::Focused => {
                         if buffer_diagnostics_editor.multibuffer.read(cx).is_empty() {
-                            window.focus(&buffer_diagnostics_editor.focus_handle);
+                            window.focus(&buffer_diagnostics_editor.focus_handle, cx);
                         }
                     }
                     EditorEvent::Blurred => {
@@ -517,7 +517,7 @@ impl BufferDiagnosticsEditor {
                                 .editor
                                 .read(cx)
                                 .focus_handle(cx)
-                                .focus(window);
+                                .focus(window, cx);
                         }
                     }
                 }
@@ -617,7 +617,7 @@ impl BufferDiagnosticsEditor {
         // not empty, focus on the editor instead, which will allow the user to
         // start interacting and editing the buffer's contents.
         if self.focus_handle.is_focused(window) && !self.multibuffer.read(cx).is_empty() {
-            self.editor.focus_handle(cx).focus(window)
+            self.editor.focus_handle(cx).focus(window, cx)
         }
     }
 

crates/diagnostics/src/diagnostic_renderer.rs πŸ”—

@@ -315,6 +315,6 @@ impl DiagnosticBlock {
         editor.change_selections(Default::default(), window, cx, |s| {
             s.select_ranges([range.start..range.start]);
         });
-        window.focus(&editor.focus_handle(cx));
+        window.focus(&editor.focus_handle(cx), cx);
     }
 }

crates/diagnostics/src/diagnostics.rs πŸ”—

@@ -243,7 +243,7 @@ impl ProjectDiagnosticsEditor {
                 match event {
                     EditorEvent::Focused => {
                         if this.multibuffer.read(cx).is_empty() {
-                            window.focus(&this.focus_handle);
+                            window.focus(&this.focus_handle, cx);
                         }
                     }
                     EditorEvent::Blurred => this.close_diagnosticless_buffers(cx, false),
@@ -434,7 +434,7 @@ impl ProjectDiagnosticsEditor {
 
     fn focus_in(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         if self.focus_handle.is_focused(window) && !self.multibuffer.read(cx).is_empty() {
-            self.editor.focus_handle(cx).focus(window)
+            self.editor.focus_handle(cx).focus(window, cx)
         }
     }
 
@@ -650,7 +650,7 @@ impl ProjectDiagnosticsEditor {
                         })
                     });
                     if this.focus_handle.is_focused(window) {
-                        this.editor.read(cx).focus_handle(cx).focus(window);
+                        this.editor.read(cx).focus_handle(cx).focus(window, cx);
                     }
                 }
 

crates/edit_prediction/src/onboarding_modal.rs πŸ”—

@@ -131,8 +131,8 @@ impl Render for ZedPredictModal {
                 onboarding_event!("Cancelled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(
                 div()

crates/edit_prediction_ui/src/rate_prediction_modal.rs πŸ”—

@@ -305,7 +305,7 @@ impl RatePredictionsModal {
                 && prediction.id == prev_prediction.prediction.id
             {
                 if focus {
-                    window.focus(&prev_prediction.feedback_editor.focus_handle(cx));
+                    window.focus(&prev_prediction.feedback_editor.focus_handle(cx), cx);
                 }
                 return;
             }

crates/editor/benches/editor_render.rs πŸ”—

@@ -29,7 +29,7 @@ fn editor_input_with_1000_cursors(bencher: &mut Bencher<'_>, cx: &TestAppContext
             );
             editor
         });
-        window.focus(&editor.focus_handle(cx));
+        window.focus(&editor.focus_handle(cx), cx);
         editor
     });
 
@@ -72,7 +72,7 @@ fn open_editor_with_one_long_line(bencher: &mut Bencher<'_>, args: &(String, Tes
                 editor.set_style(editor::EditorStyle::default(), window, cx);
                 editor
             });
-            window.focus(&editor.focus_handle(cx));
+            window.focus(&editor.focus_handle(cx), cx);
             editor
         });
     });
@@ -100,7 +100,7 @@ fn editor_render(bencher: &mut Bencher<'_>, cx: &TestAppContext) {
             editor.set_style(editor::EditorStyle::default(), window, cx);
             editor
         });
-        window.focus(&editor.focus_handle(cx));
+        window.focus(&editor.focus_handle(cx), cx);
         editor
     });
 

crates/editor/src/editor.rs πŸ”—

@@ -3816,7 +3816,7 @@ impl Editor {
     ) {
         if !self.focus_handle.is_focused(window) {
             self.last_focused_descendant = None;
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
         }
 
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -3921,7 +3921,7 @@ impl Editor {
     ) {
         if !self.focus_handle.is_focused(window) {
             self.last_focused_descendant = None;
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
         }
 
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -6712,7 +6712,7 @@ impl Editor {
                 })
             })
             .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
-                window.focus(&editor.focus_handle(cx));
+                window.focus(&editor.focus_handle(cx), cx);
                 editor.toggle_code_actions(
                     &crate::actions::ToggleCodeActions {
                         deployed_from: Some(crate::actions::CodeActionSource::Indicator(
@@ -8605,7 +8605,7 @@ impl Editor {
                         BreakpointEditAction::Toggle
                     };
 
-                    window.focus(&editor.focus_handle(cx));
+                    window.focus(&editor.focus_handle(cx), cx);
                     editor.edit_breakpoint_at_anchor(
                         position,
                         breakpoint.as_ref().clone(),
@@ -8797,7 +8797,7 @@ impl Editor {
                 ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
             };
 
-            window.focus(&editor.focus_handle(cx));
+            window.focus(&editor.focus_handle(cx), cx);
             editor.toggle_code_actions(
                 &ToggleCodeActions {
                     deployed_from: Some(CodeActionSource::RunMenu(row)),
@@ -11212,7 +11212,7 @@ impl Editor {
         }];
 
         let focus_handle = bp_prompt.focus_handle(cx);
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
 
         let block_ids = self.insert_blocks(blocks, None, cx);
         bp_prompt.update(cx, |prompt, _| {
@@ -18039,7 +18039,7 @@ impl Editor {
                         cx,
                     );
                     let rename_focus_handle = rename_editor.focus_handle(cx);
-                    window.focus(&rename_focus_handle);
+                    window.focus(&rename_focus_handle, cx);
                     let block_id = this.insert_blocks(
                         [BlockProperties {
                             style: BlockStyle::Flex,
@@ -18153,7 +18153,7 @@ impl Editor {
     ) -> Option<RenameState> {
         let rename = self.pending_rename.take()?;
         if rename.editor.focus_handle(cx).is_focused(window) {
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
         }
 
         self.remove_blocks(
@@ -22723,7 +22723,7 @@ impl Editor {
             .take()
             .and_then(|descendant| descendant.upgrade())
         {
-            window.focus(&descendant);
+            window.focus(&descendant, cx);
         } else {
             if let Some(blame) = self.blame.as_ref() {
                 blame.update(cx, GitBlame::focus)
@@ -25969,7 +25969,7 @@ impl BreakpointPromptEditor {
         self.editor
             .update(cx, |editor, cx| {
                 editor.remove_blocks(self.block_ids.clone(), None, cx);
-                window.focus(&editor.focus_handle);
+                window.focus(&editor.focus_handle, cx);
             })
             .log_err();
     }

crates/editor/src/editor_tests.rs πŸ”—

@@ -18201,7 +18201,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut TestAppContext) {
     );
 
     editor_handle.update_in(cx, |editor, window, cx| {
-        window.focus(&editor.focus_handle(cx));
+        window.focus(&editor.focus_handle(cx), cx);
         editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
             s.select_ranges([Point::new(0, 21)..Point::new(0, 20)])
         });

crates/editor/src/hover_links.rs πŸ”—

@@ -218,7 +218,7 @@ impl Editor {
             self.hide_hovered_link(cx);
             if !hovered_link_state.links.is_empty() {
                 if !self.focus_handle.is_focused(window) {
-                    window.focus(&self.focus_handle);
+                    window.focus(&self.focus_handle, cx);
                 }
 
                 // exclude links pointing back to the current anchor

crates/editor/src/mouse_context_menu.rs πŸ”—

@@ -90,8 +90,8 @@ impl MouseContextMenu {
         // `true` when the `ContextMenu` is focused.
         let focus_handle = context_menu_focus.clone();
         cx.on_next_frame(window, move |_, window, cx| {
-            cx.on_next_frame(window, move |_, window, _cx| {
-                window.focus(&focus_handle);
+            cx.on_next_frame(window, move |_, window, cx| {
+                window.focus(&focus_handle, cx);
             });
         });
 
@@ -100,7 +100,7 @@ impl MouseContextMenu {
             move |editor, _, _event: &DismissEvent, window, cx| {
                 editor.mouse_context_menu.take();
                 if context_menu_focus.contains_focused(window, cx) {
-                    window.focus(&editor.focus_handle(cx));
+                    window.focus(&editor.focus_handle(cx), cx);
                 }
             }
         });
@@ -127,7 +127,7 @@ impl MouseContextMenu {
                 }
                 editor.mouse_context_menu.take();
                 if context_menu_focus.contains_focused(window, cx) {
-                    window.focus(&editor.focus_handle(cx));
+                    window.focus(&editor.focus_handle(cx), cx);
                 }
             },
         );
@@ -161,7 +161,7 @@ pub fn deploy_context_menu(
     cx: &mut Context<Editor>,
 ) {
     if !editor.is_focused(window) {
-        window.focus(&editor.focus_handle(cx));
+        window.focus(&editor.focus_handle(cx), cx);
     }
 
     // Don't show context menu for inline editors

crates/editor/src/test/editor_lsp_test_context.rs πŸ”—

@@ -126,7 +126,7 @@ impl EditorLspTestContext {
                 .read(cx)
                 .nav_history_for_item(&cx.entity());
             editor.set_nav_history(Some(nav_history));
-            window.focus(&editor.focus_handle(cx))
+            window.focus(&editor.focus_handle(cx), cx)
         });
 
         let lsp = fake_servers.next().await.unwrap();

crates/editor/src/test/editor_test_context.rs πŸ”—

@@ -78,7 +78,7 @@ impl EditorTestContext {
                 cx,
             );
 
-            window.focus(&editor.focus_handle(cx));
+            window.focus(&editor.focus_handle(cx), cx);
             editor
         });
         let editor_view = editor.root(cx).unwrap();
@@ -139,7 +139,7 @@ impl EditorTestContext {
 
         let editor = cx.add_window(|window, cx| {
             let editor = build_editor(buffer, window, cx);
-            window.focus(&editor.focus_handle(cx));
+            window.focus(&editor.focus_handle(cx), cx);
 
             editor
         });

crates/file_finder/src/file_finder.rs πŸ”—

@@ -1713,7 +1713,7 @@ impl PickerDelegate for FileFinderDelegate {
                                                 ui::IconPosition::End,
                                                 Some(ToggleIncludeIgnored.boxed_clone()),
                                                 move |window, cx| {
-                                                    window.focus(&focus_handle);
+                                                    window.focus(&focus_handle, cx);
                                                     window.dispatch_action(
                                                         ToggleIncludeIgnored.boxed_clone(),
                                                         cx,

crates/git_ui/src/branch_picker.rs πŸ”—

@@ -91,7 +91,7 @@ pub fn popover(
             window,
             cx,
         );
-        list.focus_handle(cx).focus(window);
+        list.focus_handle(cx).focus(window, cx);
         list
     })
 }
@@ -1880,7 +1880,7 @@ mod tests {
 
         branch_list
             .update_in(cx, |branch_list, window, cx| {
-                window.focus(&branch_list.picker_focus_handle);
+                window.focus(&branch_list.picker_focus_handle, cx);
                 assert!(
                     branch_list.picker_focus_handle.is_focused(window),
                     "Branch picker should be focused when selecting an entry"
@@ -1898,7 +1898,7 @@ mod tests {
 
         branch_list.update_in(cx, |branch_list, window, cx| {
             // Re-focus the picker since workspace initialization during run_until_parked
-            window.focus(&branch_list.picker_focus_handle);
+            window.focus(&branch_list.picker_focus_handle, cx);
 
             branch_list.picker.update(cx, |picker, cx| {
                 let last_match = picker.delegate.matches.last().unwrap();

crates/git_ui/src/commit_modal.rs πŸ”—

@@ -521,7 +521,7 @@ impl CommitModal {
 
     fn toggle_branch_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         if self.branch_list_handle.is_focused(window, cx) {
-            self.focus_handle(cx).focus(window)
+            self.focus_handle(cx).focus(window, cx)
         } else {
             self.branch_list_handle.toggle(window, cx);
         }
@@ -587,8 +587,8 @@ impl Render for CommitModal {
                     .bg(cx.theme().colors().editor_background)
                     .border_1()
                     .border_color(cx.theme().colors().border_variant)
-                    .on_click(cx.listener(move |_, _: &ClickEvent, window, _cx| {
-                        window.focus(&editor_focus_handle);
+                    .on_click(cx.listener(move |_, _: &ClickEvent, window, cx| {
+                        window.focus(&editor_focus_handle, cx);
                     }))
                     .child(
                         div()

crates/git_ui/src/file_history_view.rs πŸ”—

@@ -633,9 +633,9 @@ impl Item for FileHistoryView {
         &mut self,
         _workspace: &mut Workspace,
         window: &mut Window,
-        _cx: &mut Context<Self>,
+        cx: &mut Context<Self>,
     ) {
-        window.focus(&self.focus_handle);
+        window.focus(&self.focus_handle, cx);
     }
 
     fn show_toolbar(&self) -> bool {

crates/git_ui/src/git_panel.rs πŸ”—

@@ -1063,7 +1063,7 @@ impl GitPanel {
 
     fn focus_editor(&mut self, _: &FocusEditor, window: &mut Window, cx: &mut Context<Self>) {
         self.commit_editor.update(cx, |editor, cx| {
-            window.focus(&editor.focus_handle(cx));
+            window.focus(&editor.focus_handle(cx), cx);
         });
         cx.notify();
     }
@@ -1084,8 +1084,7 @@ impl GitPanel {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        self.focus_handle.focus(window);
-
+        self.focus_handle.focus(window, cx);
         self.select_first_entry_if_none(window, cx);
     }
 
@@ -1107,7 +1106,7 @@ impl GitPanel {
                         .project_path_to_repo_path(&project_path, cx)
                         .as_ref()
             {
-                project_diff.focus_handle(cx).focus(window);
+                project_diff.focus_handle(cx).focus(window, cx);
                 project_diff.update(cx, |project_diff, cx| project_diff.autoscroll(cx));
                 return None;
             };
@@ -1117,7 +1116,7 @@ impl GitPanel {
                     ProjectDiff::deploy_at(workspace, Some(entry.clone()), window, cx);
                 })
                 .ok();
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
 
             Some(())
         });
@@ -2128,7 +2127,10 @@ impl GitPanel {
         let commit_message = self.custom_or_suggested_commit_message(window, cx);
 
         let Some(mut message) = commit_message else {
-            self.commit_editor.read(cx).focus_handle(cx).focus(window);
+            self.commit_editor
+                .read(cx)
+                .focus_handle(cx)
+                .focus(window, cx);
             return;
         };
 
@@ -4146,7 +4148,7 @@ impl GitPanel {
                     .border_color(cx.theme().colors().border)
                     .cursor_text()
                     .on_click(cx.listener(move |this, _: &ClickEvent, window, cx| {
-                        window.focus(&this.commit_editor.focus_handle(cx));
+                        window.focus(&this.commit_editor.focus_handle(cx), cx);
                     }))
                     .child(
                         h_flex()
@@ -4940,7 +4942,7 @@ impl GitPanel {
                         this.open_file(&Default::default(), window, cx)
                     } else {
                         this.open_diff(&Default::default(), window, cx);
-                        this.focus_handle.focus(window);
+                        this.focus_handle.focus(window, cx);
                     }
                 })
             })

crates/git_ui/src/git_ui.rs πŸ”—

@@ -817,7 +817,7 @@ impl GitCloneModal {
         });
         let focus_handle = repo_input.focus_handle(cx);
 
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
 
         Self {
             panel,

crates/git_ui/src/onboarding.rs πŸ”—

@@ -85,8 +85,8 @@ impl Render for GitOnboardingModal {
                 git_onboarding_event!("Cancelled", trigger = "Action");
                 cx.emit(DismissEvent);
             }))
-            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
-                this.focus_handle.focus(window);
+            .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
+                this.focus_handle.focus(window, cx);
             }))
             .child(
                 div().p_1p5().absolute().inset_0().h(px(160.)).child(

crates/git_ui/src/project_diff.rs πŸ”—

@@ -492,7 +492,7 @@ impl ProjectDiff {
         if editor.focus_handle(cx).contains_focused(window, cx)
             && self.multibuffer.read(cx).is_empty()
         {
-            self.focus_handle.focus(window)
+            self.focus_handle.focus(window, cx)
         }
     }
 
@@ -597,10 +597,10 @@ impl ProjectDiff {
                 .focus_handle(cx)
                 .contains_focused(window, cx)
         {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         } else if self.focus_handle.is_focused(window) && !self.multibuffer.read(cx).is_empty() {
             self.editor.update(cx, |editor, cx| {
-                editor.focus_handle(cx).focus(window);
+                editor.focus_handle(cx).focus(window, cx);
             });
         }
         if self.pending_scroll.as_ref() == Some(&path_key) {
@@ -983,7 +983,7 @@ impl Render for ProjectDiff {
                                         cx,
                                     ))
                                     .on_click(move |_, window, cx| {
-                                        window.focus(&keybinding_focus_handle);
+                                        window.focus(&keybinding_focus_handle, cx);
                                         window.dispatch_action(
                                             Box::new(CloseActiveItem::default()),
                                             cx,
@@ -1153,7 +1153,7 @@ impl ProjectDiffToolbar {
 
     fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut Context<Self>) {
         if let Some(project_diff) = self.project_diff(cx) {
-            project_diff.focus_handle(cx).focus(window);
+            project_diff.focus_handle(cx).focus(window, cx);
         }
         let action = action.boxed_clone();
         cx.defer(move |cx| {

crates/go_to_line/src/go_to_line.rs πŸ”—

@@ -268,7 +268,7 @@ impl GoToLine {
                 cx,
                 |s| s.select_anchor_ranges([start..start]),
             );
-            editor.focus_handle(cx).focus(window);
+            editor.focus_handle(cx).focus(window, cx);
             cx.notify()
         });
         self.prev_scroll_position.take();

crates/gpui/examples/focus_visible.rs πŸ”—

@@ -29,7 +29,7 @@ impl Example {
         ];
 
         let focus_handle = cx.focus_handle();
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
 
         Self {
             focus_handle,
@@ -40,13 +40,13 @@ impl Example {
         }
     }
 
-    fn on_tab(&mut self, _: &Tab, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_next();
+    fn on_tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_next(cx);
         self.message = SharedString::from("Pressed Tab - focus-visible border should appear!");
     }
 
-    fn on_tab_prev(&mut self, _: &TabPrev, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_prev();
+    fn on_tab_prev(&mut self, _: &TabPrev, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_prev(cx);
         self.message =
             SharedString::from("Pressed Shift-Tab - focus-visible border should appear!");
     }

crates/gpui/examples/input.rs πŸ”—

@@ -736,7 +736,7 @@ fn main() {
 
         window
             .update(cx, |view, window, cx| {
-                window.focus(&view.text_input.focus_handle(cx));
+                window.focus(&view.text_input.focus_handle(cx), cx);
                 cx.activate(true);
             })
             .unwrap();

crates/gpui/examples/on_window_close_quit.rs πŸ”—

@@ -55,7 +55,7 @@ fn main() {
                 cx.activate(false);
                 cx.new(|cx| {
                     let focus_handle = cx.focus_handle();
-                    focus_handle.focus(window);
+                    focus_handle.focus(window, cx);
                     ExampleWindow { focus_handle }
                 })
             },
@@ -72,7 +72,7 @@ fn main() {
             |window, cx| {
                 cx.new(|cx| {
                     let focus_handle = cx.focus_handle();
-                    focus_handle.focus(window);
+                    focus_handle.focus(window, cx);
                     ExampleWindow { focus_handle }
                 })
             },

crates/gpui/examples/tab_stop.rs πŸ”—

@@ -22,7 +22,7 @@ impl Example {
         ];
 
         let focus_handle = cx.focus_handle();
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
 
         Self {
             focus_handle,
@@ -31,13 +31,13 @@ impl Example {
         }
     }
 
-    fn on_tab(&mut self, _: &Tab, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_next();
+    fn on_tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_next(cx);
         self.message = SharedString::from("You have pressed `Tab`.");
     }
 
-    fn on_tab_prev(&mut self, _: &TabPrev, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_prev();
+    fn on_tab_prev(&mut self, _: &TabPrev, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_prev(cx);
         self.message = SharedString::from("You have pressed `Shift-Tab`.");
     }
 }

crates/gpui/src/app.rs πŸ”—

@@ -1900,8 +1900,11 @@ impl App {
     pub(crate) fn clear_pending_keystrokes(&mut self) {
         for window in self.windows() {
             window
-                .update(self, |_, window, _| {
-                    window.clear_pending_keystrokes();
+                .update(self, |_, window, cx| {
+                    if window.pending_input_keystrokes().is_some() {
+                        window.clear_pending_keystrokes();
+                        window.pending_input_changed(cx);
+                    }
                 })
                 .ok();
         }

crates/gpui/src/app/async_context.rs πŸ”—

@@ -487,7 +487,7 @@ impl VisualContext for AsyncWindowContext {
         V: Focusable,
     {
         self.app.update_window(self.window, |_, window, cx| {
-            view.read(cx).focus_handle(cx).focus(window);
+            view.read(cx).focus_handle(cx).focus(window, cx);
         })
     }
 }

crates/gpui/src/app/context.rs πŸ”—

@@ -285,7 +285,7 @@ impl<'a, T: 'static> Context<'a, T> {
 
     /// Focus the given view in the given window. View type is required to implement Focusable.
     pub fn focus_view<W: Focusable>(&mut self, view: &Entity<W>, window: &mut Window) {
-        window.focus(&view.focus_handle(self));
+        window.focus(&view.focus_handle(self), self);
     }
 
     /// Sets a given callback to be run on the next frame.
@@ -732,7 +732,7 @@ impl<'a, T: 'static> Context<'a, T> {
     {
         let view = self.entity();
         window.defer(self, move |window, cx| {
-            view.read(cx).focus_handle(cx).focus(window)
+            view.read(cx).focus_handle(cx).focus(window, cx)
         })
     }
 }

crates/gpui/src/app/test_context.rs πŸ”—

@@ -1045,7 +1045,7 @@ impl VisualContext for VisualTestContext {
     fn focus<V: crate::Focusable>(&mut self, view: &Entity<V>) -> Self::Result<()> {
         self.window
             .update(&mut self.cx, |_, window, cx| {
-                view.read(cx).focus_handle(cx).focus(window)
+                view.read(cx).focus_handle(cx).focus(window, cx)
             })
             .unwrap()
     }

crates/gpui/src/elements/div.rs πŸ”—

@@ -654,7 +654,7 @@ pub trait InteractiveElement: Sized {
     /// Set whether this element is a tab stop.
     ///
     /// When false, the element remains in tab-index order but cannot be reached via keyboard navigation.
-    /// Useful for container elements: focus the container, then call `window.focus_next()` to focus
+    /// Useful for container elements: focus the container, then call `window.focus_next(cx)` to focus
     /// the first tab stop inside it while having the container element itself be unreachable via the keyboard.
     /// Should only be used with `tab_index`.
     fn tab_stop(mut self, tab_stop: bool) -> Self {
@@ -2096,12 +2096,12 @@ impl Interactivity {
         // This behavior can be suppressed by using `cx.prevent_default()`.
         if let Some(focus_handle) = self.tracked_focus_handle.clone() {
             let hitbox = hitbox.clone();
-            window.on_mouse_event(move |_: &MouseDownEvent, phase, window, _| {
+            window.on_mouse_event(move |_: &MouseDownEvent, phase, window, cx| {
                 if phase == DispatchPhase::Bubble
                     && hitbox.is_hovered(window)
                     && !window.default_prevented()
                 {
-                    window.focus(&focus_handle);
+                    window.focus(&focus_handle, cx);
                     // If there is a parent that is also focusable, prevent it
                     // from transferring focus because we already did so.
                     window.prevent_default();

crates/gpui/src/elements/uniform_list.rs πŸ”—

@@ -788,7 +788,7 @@ mod test {
 
         let (view, cx) = cx.add_window_view(|window, cx| {
             let focus_handle = cx.focus_handle();
-            window.focus(&focus_handle);
+            window.focus(&focus_handle, cx);
             TestView {
                 scroll_handle: UniformListScrollHandle::new(),
                 index: 0,

crates/gpui/src/interactive.rs πŸ”—

@@ -705,8 +705,8 @@ mod test {
         });
 
         window
-            .update(cx, |test_view, window, _cx| {
-                window.focus(&test_view.focus_handle)
+            .update(cx, |test_view, window, cx| {
+                window.focus(&test_view.focus_handle, cx)
             })
             .unwrap();
 

crates/gpui/src/key_dispatch.rs πŸ”—

@@ -610,8 +610,8 @@ impl DispatchTree {
 #[cfg(test)]
 mod tests {
     use crate::{
-        self as gpui, DispatchResult, Element, ElementId, GlobalElementId, InspectorElementId,
-        Keystroke, LayoutId, Style,
+        self as gpui, AppContext, DispatchResult, Element, ElementId, GlobalElementId,
+        InspectorElementId, Keystroke, LayoutId, Style,
     };
     use core::panic;
     use smallvec::SmallVec;
@@ -619,8 +619,8 @@ mod tests {
 
     use crate::{
         Action, ActionRegistry, App, Bounds, Context, DispatchTree, FocusHandle, InputHandler,
-        IntoElement, KeyBinding, KeyContext, Keymap, Pixels, Point, Render, TestAppContext,
-        UTF16Selection, Window,
+        IntoElement, KeyBinding, KeyContext, Keymap, Pixels, Point, Render, Subscription,
+        TestAppContext, UTF16Selection, Window,
     };
 
     #[derive(PartialEq, Eq)]
@@ -723,6 +723,213 @@ mod tests {
         assert!(!result.pending_has_binding);
     }
 
+    #[crate::test]
+    fn test_pending_input_observers_notified_on_focus_change(cx: &mut TestAppContext) {
+        #[derive(Clone)]
+        struct CustomElement {
+            focus_handle: FocusHandle,
+            text: Rc<RefCell<String>>,
+        }
+
+        impl CustomElement {
+            fn new(cx: &mut Context<Self>) -> Self {
+                Self {
+                    focus_handle: cx.focus_handle(),
+                    text: Rc::default(),
+                }
+            }
+        }
+
+        impl Element for CustomElement {
+            type RequestLayoutState = ();
+
+            type PrepaintState = ();
+
+            fn id(&self) -> Option<ElementId> {
+                Some("custom".into())
+            }
+
+            fn source_location(&self) -> Option<&'static panic::Location<'static>> {
+                None
+            }
+
+            fn request_layout(
+                &mut self,
+                _: Option<&GlobalElementId>,
+                _: Option<&InspectorElementId>,
+                window: &mut Window,
+                cx: &mut App,
+            ) -> (LayoutId, Self::RequestLayoutState) {
+                (window.request_layout(Style::default(), [], cx), ())
+            }
+
+            fn prepaint(
+                &mut self,
+                _: Option<&GlobalElementId>,
+                _: Option<&InspectorElementId>,
+                _: Bounds<Pixels>,
+                _: &mut Self::RequestLayoutState,
+                window: &mut Window,
+                cx: &mut App,
+            ) -> Self::PrepaintState {
+                window.set_focus_handle(&self.focus_handle, cx);
+            }
+
+            fn paint(
+                &mut self,
+                _: Option<&GlobalElementId>,
+                _: Option<&InspectorElementId>,
+                _: Bounds<Pixels>,
+                _: &mut Self::RequestLayoutState,
+                _: &mut Self::PrepaintState,
+                window: &mut Window,
+                cx: &mut App,
+            ) {
+                let mut key_context = KeyContext::default();
+                key_context.add("Terminal");
+                window.set_key_context(key_context);
+                window.handle_input(&self.focus_handle, self.clone(), cx);
+                window.on_action(std::any::TypeId::of::<TestAction>(), |_, _, _, _| {});
+            }
+        }
+
+        impl IntoElement for CustomElement {
+            type Element = Self;
+
+            fn into_element(self) -> Self::Element {
+                self
+            }
+        }
+
+        impl InputHandler for CustomElement {
+            fn selected_text_range(
+                &mut self,
+                _: bool,
+                _: &mut Window,
+                _: &mut App,
+            ) -> Option<UTF16Selection> {
+                None
+            }
+
+            fn marked_text_range(&mut self, _: &mut Window, _: &mut App) -> Option<Range<usize>> {
+                None
+            }
+
+            fn text_for_range(
+                &mut self,
+                _: Range<usize>,
+                _: &mut Option<Range<usize>>,
+                _: &mut Window,
+                _: &mut App,
+            ) -> Option<String> {
+                None
+            }
+
+            fn replace_text_in_range(
+                &mut self,
+                replacement_range: Option<Range<usize>>,
+                text: &str,
+                _: &mut Window,
+                _: &mut App,
+            ) {
+                if replacement_range.is_some() {
+                    unimplemented!()
+                }
+                self.text.borrow_mut().push_str(text)
+            }
+
+            fn replace_and_mark_text_in_range(
+                &mut self,
+                replacement_range: Option<Range<usize>>,
+                new_text: &str,
+                _: Option<Range<usize>>,
+                _: &mut Window,
+                _: &mut App,
+            ) {
+                if replacement_range.is_some() {
+                    unimplemented!()
+                }
+                self.text.borrow_mut().push_str(new_text)
+            }
+
+            fn unmark_text(&mut self, _: &mut Window, _: &mut App) {}
+
+            fn bounds_for_range(
+                &mut self,
+                _: Range<usize>,
+                _: &mut Window,
+                _: &mut App,
+            ) -> Option<Bounds<Pixels>> {
+                None
+            }
+
+            fn character_index_for_point(
+                &mut self,
+                _: Point<Pixels>,
+                _: &mut Window,
+                _: &mut App,
+            ) -> Option<usize> {
+                None
+            }
+        }
+
+        impl Render for CustomElement {
+            fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
+                self.clone()
+            }
+        }
+
+        cx.update(|cx| {
+            cx.bind_keys([KeyBinding::new("ctrl-b", TestAction, Some("Terminal"))]);
+            cx.bind_keys([KeyBinding::new("ctrl-b h", TestAction, Some("Terminal"))]);
+        });
+
+        let (test, cx) = cx.add_window_view(|_, cx| CustomElement::new(cx));
+        let focus_handle = test.update(cx, |test, _| test.focus_handle.clone());
+
+        let pending_input_changed_count = Rc::new(RefCell::new(0usize));
+        let pending_input_changed_count_for_observer = pending_input_changed_count.clone();
+
+        struct PendingInputObserver {
+            _subscription: Subscription,
+        }
+
+        let _observer = cx.update(|window, cx| {
+            cx.new(|cx| PendingInputObserver {
+                _subscription: cx.observe_pending_input(window, move |_, _, _| {
+                    *pending_input_changed_count_for_observer.borrow_mut() += 1;
+                }),
+            })
+        });
+
+        cx.update(|window, cx| {
+            window.focus(&focus_handle, cx);
+            window.activate_window();
+        });
+
+        cx.simulate_keystrokes("ctrl-b");
+
+        let count_after_pending = Rc::new(RefCell::new(0usize));
+        let count_after_pending_for_assertion = count_after_pending.clone();
+
+        cx.update(|window, cx| {
+            assert!(window.has_pending_keystrokes());
+            *count_after_pending.borrow_mut() = *pending_input_changed_count.borrow();
+            assert!(*count_after_pending.borrow() > 0);
+
+            window.focus(&cx.focus_handle(), cx);
+
+            assert!(!window.has_pending_keystrokes());
+        });
+
+        // Focus-triggered pending-input notifications are deferred to the end of the current
+        // effect cycle, so the observer callback should run after the focus update completes.
+        cx.update(|_, _| {
+            let count_after_focus_change = *pending_input_changed_count.borrow();
+            assert!(count_after_focus_change > *count_after_pending_for_assertion.borrow());
+        });
+    }
+
     #[crate::test]
     fn test_input_handler_pending(cx: &mut TestAppContext) {
         #[derive(Clone)]
@@ -876,8 +1083,9 @@ mod tests {
             cx.bind_keys([KeyBinding::new("ctrl-b h", TestAction, Some("Terminal"))]);
         });
         let (test, cx) = cx.add_window_view(|_, cx| CustomElement::new(cx));
+        let focus_handle = test.update(cx, |test, _| test.focus_handle.clone());
         cx.update(|window, cx| {
-            window.focus(&test.read(cx).focus_handle);
+            window.focus(&focus_handle, cx);
             window.activate_window();
         });
         cx.simulate_keystrokes("ctrl-b [");

crates/gpui/src/window.rs πŸ”—

@@ -345,8 +345,8 @@ impl FocusHandle {
     }
 
     /// Moves the focus to the element associated with this handle.
-    pub fn focus(&self, window: &mut Window) {
-        window.focus(self)
+    pub fn focus(&self, window: &mut Window, cx: &mut App) {
+        window.focus(self, cx)
     }
 
     /// Obtains whether the element associated with this handle is currently focused.
@@ -1436,13 +1436,25 @@ impl Window {
     }
 
     /// Move focus to the element associated with the given [`FocusHandle`].
-    pub fn focus(&mut self, handle: &FocusHandle) {
+    pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
         if !self.focus_enabled || self.focus == Some(handle.id) {
             return;
         }
 
         self.focus = Some(handle.id);
         self.clear_pending_keystrokes();
+
+        // Avoid re-entrant entity updates by deferring observer notifications to the end of the
+        // current effect cycle, and only for this window.
+        let window_handle = self.handle;
+        cx.defer(move |cx| {
+            window_handle
+                .update(cx, |_, window, cx| {
+                    window.pending_input_changed(cx);
+                })
+                .ok();
+        });
+
         self.refresh();
     }
 
@@ -1463,24 +1475,24 @@ impl Window {
     }
 
     /// Move focus to next tab stop.
-    pub fn focus_next(&mut self) {
+    pub fn focus_next(&mut self, cx: &mut App) {
         if !self.focus_enabled {
             return;
         }
 
         if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
-            self.focus(&handle)
+            self.focus(&handle, cx)
         }
     }
 
     /// Move focus to previous tab stop.
-    pub fn focus_prev(&mut self) {
+    pub fn focus_prev(&mut self, cx: &mut App) {
         if !self.focus_enabled {
             return;
         }
 
         if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
-            self.focus(&handle)
+            self.focus(&handle, cx)
         }
     }
 
@@ -4020,7 +4032,7 @@ impl Window {
         self.dispatch_keystroke_observers(event, None, context_stack, cx);
     }
 
-    fn pending_input_changed(&mut self, cx: &mut App) {
+    pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
         self.pending_input_observers
             .clone()
             .retain(&(), |callback| callback(self, cx));

crates/gpui/src/window/prompts.rs πŸ”—

@@ -44,10 +44,10 @@ impl PromptHandle {
             if let Some(sender) = sender.take() {
                 sender.send(e.0).ok();
                 window_handle
-                    .update(cx, |_, window, _cx| {
+                    .update(cx, |_, window, cx| {
                         window.prompt.take();
                         if let Some(previous_focus) = &previous_focus {
-                            window.focus(previous_focus);
+                            window.focus(previous_focus, cx);
                         }
                     })
                     .ok();
@@ -55,7 +55,7 @@ impl PromptHandle {
         })
         .detach();
 
-        window.focus(&view.focus_handle(cx));
+        window.focus(&view.focus_handle(cx), cx);
 
         RenderablePromptHandle {
             view: Box::new(view),

crates/gpui_macros/src/derive_visual_context.rs πŸ”—

@@ -62,7 +62,7 @@ pub fn derive_visual_context(input: TokenStream) -> TokenStream {
                 V: gpui::Focusable,
             {
                 let focus_handle = gpui::Focusable::focus_handle(entity, self.#app_variable);
-                self.#window_variable.focus(&focus_handle)
+                self.#window_variable.focus(&focus_handle, self.#app_variable)
             }
         }
     };

crates/keymap_editor/src/keymap_editor.rs πŸ”—

@@ -911,7 +911,7 @@ impl KeymapEditor {
             .focus_handle(cx)
             .contains_focused(window, cx)
         {
-            window.focus(&self.filter_editor.focus_handle(cx));
+            window.focus(&self.filter_editor.focus_handle(cx), cx);
         } else {
             self.filter_editor.update(cx, |editor, cx| {
                 editor.select_all(&Default::default(), window, cx);
@@ -948,7 +948,7 @@ impl KeymapEditor {
             if let Some(scroll_strategy) = scroll {
                 self.scroll_to_item(index, scroll_strategy, cx);
             }
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
             cx.notify();
         }
     }
@@ -998,7 +998,7 @@ impl KeymapEditor {
             });
 
             let context_menu_handle = context_menu.focus_handle(cx);
-            window.defer(cx, move |window, _cx| window.focus(&context_menu_handle));
+            window.defer(cx, move |window, cx| window.focus(&context_menu_handle, cx));
             let subscription = cx.subscribe_in(
                 &context_menu,
                 window,
@@ -1014,7 +1014,7 @@ impl KeymapEditor {
 
     fn dismiss_context_menu(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.context_menu.take();
-        window.focus(&self.focus_handle);
+        window.focus(&self.focus_handle, cx);
         cx.notify();
     }
 
@@ -1230,7 +1230,7 @@ impl KeymapEditor {
                         window,
                         cx,
                     );
-                    window.focus(&modal.focus_handle(cx));
+                    window.focus(&modal.focus_handle(cx), cx);
                     modal
                 });
             })
@@ -1338,7 +1338,7 @@ impl KeymapEditor {
                     editor.stop_recording(&StopRecording, window, cx);
                     editor.clear_keystrokes(&ClearKeystrokes, window, cx);
                 });
-                window.focus(&self.filter_editor.focus_handle(cx));
+                window.focus(&self.filter_editor.focus_handle(cx), cx);
             }
         }
     }
@@ -2698,32 +2698,32 @@ impl KeybindingEditorModalFocusState {
             .map(|i| i as i32)
     }
 
-    fn focus_index(&self, mut index: i32, window: &mut Window) {
+    fn focus_index(&self, mut index: i32, window: &mut Window, cx: &mut App) {
         if index < 0 {
             index = self.handles.len() as i32 - 1;
         }
         if index >= self.handles.len() as i32 {
             index = 0;
         }
-        window.focus(&self.handles[index as usize]);
+        window.focus(&self.handles[index as usize], cx);
     }
 
-    fn focus_next(&self, window: &mut Window, cx: &App) {
+    fn focus_next(&self, window: &mut Window, cx: &mut App) {
         let index_to_focus = if let Some(index) = self.focused_index(window, cx) {
             index + 1
         } else {
             0
         };
-        self.focus_index(index_to_focus, window);
+        self.focus_index(index_to_focus, window, cx);
     }
 
-    fn focus_previous(&self, window: &mut Window, cx: &App) {
+    fn focus_previous(&self, window: &mut Window, cx: &mut App) {
         let index_to_focus = if let Some(index) = self.focused_index(window, cx) {
             index - 1
         } else {
             self.handles.len() as i32 - 1
         };
-        self.focus_index(index_to_focus, window);
+        self.focus_index(index_to_focus, window, cx);
     }
 }
 
@@ -2757,7 +2757,7 @@ impl ActionArgumentsEditor {
     ) -> Self {
         let focus_handle = cx.focus_handle();
         cx.on_focus_in(&focus_handle, window, |this, window, cx| {
-            this.editor.focus_handle(cx).focus(window);
+            this.editor.focus_handle(cx).focus(window, cx);
         })
         .detach();
         let editor = cx.new(|cx| {
@@ -2810,7 +2810,7 @@ impl ActionArgumentsEditor {
 
                 this.update_in(cx, |this, window, cx| {
                     if this.editor.focus_handle(cx).is_focused(window) {
-                        editor.focus_handle(cx).focus(window);
+                        editor.focus_handle(cx).focus(window, cx);
                     }
                     this.editor = editor;
                     this.backup_temp_dir = backup_temp_dir;

crates/keymap_editor/src/ui_components/keystroke_input.rs πŸ”—

@@ -388,7 +388,7 @@ impl KeystrokeInput {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        window.focus(&self.inner_focus_handle);
+        window.focus(&self.inner_focus_handle, cx);
         self.clear_keystrokes(&ClearKeystrokes, window, cx);
         self.previous_modifiers = window.modifiers();
         #[cfg(test)]
@@ -407,7 +407,7 @@ impl KeystrokeInput {
         if !self.is_recording(window) {
             return;
         }
-        window.focus(&self.outer_focus_handle);
+        window.focus(&self.outer_focus_handle, cx);
         if let Some(close_keystrokes_start) = self.close_keystrokes_start.take()
             && close_keystrokes_start < self.keystrokes.len()
         {

crates/language_models/src/provider/bedrock.rs πŸ”—

@@ -1298,17 +1298,17 @@ impl ConfigurationView {
         self.state.read(cx).is_authenticated()
     }
 
-    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, _: &mut Context<Self>) {
-        window.focus_next();
+    fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, cx: &mut Context<Self>) {
+        window.focus_next(cx);
     }
 
     fn on_tab_prev(
         &mut self,
         _: &menu::SelectPrevious,
         window: &mut Window,
-        _: &mut Context<Self>,
+        cx: &mut Context<Self>,
     ) {
-        window.focus_prev();
+        window.focus_prev(cx);
     }
 }
 

crates/language_tools/src/lsp_log_view.rs πŸ”—

@@ -269,7 +269,7 @@ impl LspLogView {
 
         let focus_handle = cx.focus_handle();
         let focus_subscription = cx.on_focus(&focus_handle, window, |log_view, window, cx| {
-            window.focus(&log_view.editor.focus_handle(cx));
+            window.focus(&log_view.editor.focus_handle(cx), cx);
         });
 
         cx.on_release(|log_view, cx| {
@@ -462,7 +462,7 @@ impl LspLogView {
             self.editor_subscriptions = editor_subscriptions;
             cx.notify();
         }
-        self.editor.read(cx).focus_handle(cx).focus(window);
+        self.editor.read(cx).focus_handle(cx).focus(window, cx);
         self.log_store.update(cx, |log_store, cx| {
             let state = log_store.get_language_server_state(server_id)?;
             state.toggled_log_kind = Some(LogKind::Logs);
@@ -494,7 +494,7 @@ impl LspLogView {
             cx.notify();
         }
 
-        self.editor.read(cx).focus_handle(cx).focus(window);
+        self.editor.read(cx).focus_handle(cx).focus(window, cx);
     }
 
     fn show_trace_for_server(
@@ -528,7 +528,7 @@ impl LspLogView {
             });
             cx.notify();
         }
-        self.editor.read(cx).focus_handle(cx).focus(window);
+        self.editor.read(cx).focus_handle(cx).focus(window, cx);
     }
 
     fn show_rpc_trace_for_server(
@@ -572,7 +572,7 @@ impl LspLogView {
             cx.notify();
         }
 
-        self.editor.read(cx).focus_handle(cx).focus(window);
+        self.editor.read(cx).focus_handle(cx).focus(window, cx);
     }
 
     fn toggle_rpc_trace_for_server(
@@ -660,7 +660,7 @@ impl LspLogView {
         self.editor = editor;
         self.editor_subscriptions = editor_subscriptions;
         cx.notify();
-        self.editor.read(cx).focus_handle(cx).focus(window);
+        self.editor.read(cx).focus_handle(cx).focus(window, cx);
         self.log_store.update(cx, |log_store, cx| {
             let state = log_store.get_language_server_state(server_id)?;
             if let Some(log_kind) = state.toggled_log_kind.take() {
@@ -1314,7 +1314,7 @@ impl LspLogToolbarItemView {
                     log_view.show_rpc_trace_for_server(id, window, cx);
                     cx.notify();
                 }
-                window.focus(&log_view.focus_handle);
+                window.focus(&log_view.focus_handle, cx);
             });
         }
         cx.notify();

crates/language_tools/src/syntax_tree_view.rs πŸ”—

@@ -659,7 +659,7 @@ impl SyntaxTreeToolbarItemView {
             buffer_state.active_layer = Some(layer.to_owned());
             view.selected_descendant_ix = None;
             cx.notify();
-            view.focus_handle.focus(window);
+            view.focus_handle.focus(window, cx);
             Some(())
         })
     }

crates/markdown/src/markdown.rs πŸ”—

@@ -707,7 +707,7 @@ impl MarkdownElement {
                                 pending: true,
                                 mode,
                             };
-                            window.focus(&markdown.focus_handle);
+                            window.focus(&markdown.focus_handle, cx);
                         }
 
                         window.prevent_default();

crates/markdown_preview/src/markdown_preview_view.rs πŸ”—

@@ -96,7 +96,7 @@ impl MarkdownPreviewView {
                         pane.add_item(Box::new(view.clone()), false, false, None, window, cx)
                     }
                 });
-                editor.focus_handle(cx).focus(window);
+                editor.focus_handle(cx).focus(window, cx);
                 cx.notify();
             }
         });
@@ -370,7 +370,7 @@ impl MarkdownPreviewView {
                     cx,
                     |selections| selections.select_ranges(vec![selection]),
                 );
-                window.focus(&editor.focus_handle(cx));
+                window.focus(&editor.focus_handle(cx), cx);
             });
         }
     }

crates/onboarding/src/onboarding.rs πŸ”—

@@ -190,7 +190,7 @@ pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyh
                 let onboarding_page = Onboarding::new(workspace, cx);
                 workspace.add_item_to_center(Box::new(onboarding_page.clone()), window, cx);
 
-                window.focus(&onboarding_page.focus_handle(cx));
+                window.focus(&onboarding_page.focus_handle(cx), cx);
 
                 cx.notify();
             };
@@ -277,11 +277,11 @@ impl Render for Onboarding {
             .on_action(Self::handle_sign_in)
             .on_action(Self::handle_open_account)
             .on_action(cx.listener(|_, _: &menu::SelectNext, window, cx| {
-                window.focus_next();
+                window.focus_next(cx);
                 cx.notify();
             }))
             .on_action(cx.listener(|_, _: &menu::SelectPrevious, window, cx| {
-                window.focus_prev();
+                window.focus_prev(cx);
                 cx.notify();
             }))
             .child(

crates/outline/src/outline.rs πŸ”—

@@ -311,7 +311,7 @@ impl PickerDelegate for OutlineViewDelegate {
                     |s| s.select_ranges([rows.start..rows.start]),
                 );
                 active_editor.clear_row_highlights::<OutlineRowHighlights>();
-                window.focus(&active_editor.focus_handle(cx));
+                window.focus(&active_editor.focus_handle(cx), cx);
             }
         });
 

crates/outline_panel/src/outline_panel.rs πŸ”—

@@ -998,9 +998,9 @@ impl OutlinePanel {
 
     fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
         if self.filter_editor.focus_handle(cx).is_focused(window) {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         } else {
-            self.filter_editor.focus_handle(cx).focus(window);
+            self.filter_editor.focus_handle(cx).focus(window, cx);
         }
 
         if self.context_menu.is_some() {
@@ -1153,9 +1153,9 @@ impl OutlinePanel {
                 }
 
                 if change_focus {
-                    active_editor.focus_handle(cx).focus(window);
+                    active_editor.focus_handle(cx).focus(window, cx);
                 } else {
-                    self.focus_handle.focus(window);
+                    self.focus_handle.focus(window, cx);
                 }
             }
         }
@@ -1458,7 +1458,7 @@ impl OutlinePanel {
                     Box::new(zed_actions::workspace::CopyRelativePath),
                 )
         });
-        window.focus(&context_menu.focus_handle(cx));
+        window.focus(&context_menu.focus_handle(cx), cx);
         let subscription = cx.subscribe(&context_menu, |outline_panel, _, _: &DismissEvent, cx| {
             outline_panel.context_menu.take();
             cx.notify();
@@ -4539,7 +4539,7 @@ impl OutlinePanel {
         cx: &mut Context<Self>,
     ) {
         if focus {
-            self.focus_handle.focus(window);
+            self.focus_handle.focus(window, cx);
         }
         let ix = self
             .cached_entries

crates/picker/src/picker.rs πŸ”—

@@ -384,7 +384,7 @@ impl<D: PickerDelegate> Picker<D> {
     }
 
     pub fn focus(&self, window: &mut Window, cx: &mut App) {
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
     }
 
     /// Handles the selecting an index, and passing the change to the delegate.

crates/project_panel/src/project_panel.rs πŸ”—

@@ -880,7 +880,7 @@ impl ProjectPanel {
                                 });
                                 if !focus_opened_item {
                                     let focus_handle = project_panel.read(cx).focus_handle.clone();
-                                    window.focus(&focus_handle);
+                                    window.focus(&focus_handle, cx);
                                 }
                             }
                         }
@@ -1169,7 +1169,7 @@ impl ProjectPanel {
                 })
             });
 
-            window.focus(&context_menu.focus_handle(cx));
+            window.focus(&context_menu.focus_handle(cx), cx);
             let subscription = cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
                 this.context_menu.take();
                 cx.notify();
@@ -1376,7 +1376,7 @@ impl ProjectPanel {
                 }
             });
             self.update_visible_entries(Some((worktree_id, entry_id)), false, false, window, cx);
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
             cx.notify();
         }
     }
@@ -1399,7 +1399,7 @@ impl ProjectPanel {
                 }
             }
             self.update_visible_entries(Some((worktree_id, entry_id)), false, false, window, cx);
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
             cx.notify();
         }
     }
@@ -1719,7 +1719,7 @@ impl ProjectPanel {
             };
             if let Some(existing) = worktree.read(cx).entry_for_path(&new_path) {
                 if existing.id == entry.id && refocus {
-                    window.focus(&self.focus_handle);
+                    window.focus(&self.focus_handle, cx);
                 }
                 return None;
             }
@@ -1730,7 +1730,7 @@ impl ProjectPanel {
         };
 
         if refocus {
-            window.focus(&self.focus_handle);
+            window.focus(&self.focus_handle, cx);
         }
         edit_state.processing_filename = Some(filename);
         cx.notify();
@@ -1839,7 +1839,7 @@ impl ProjectPanel {
             self.autoscroll(cx);
         }
 
-        window.focus(&self.focus_handle);
+        window.focus(&self.focus_handle, cx);
         cx.notify();
     }
 
@@ -3616,7 +3616,7 @@ impl ProjectPanel {
                 if this.update_visible_entries_task.focus_filename_editor {
                     this.update_visible_entries_task.focus_filename_editor = false;
                     this.filename_editor.update(cx, |editor, cx| {
-                        window.focus(&editor.focus_handle(cx));
+                        window.focus(&editor.focus_handle(cx), cx);
                     });
                 }
                 if this.update_visible_entries_task.autoscroll {
@@ -5952,7 +5952,7 @@ impl Render for ProjectPanel {
                                     cx.stop_propagation();
                                     this.state.selection = None;
                                     this.marked_entries.clear();
-                                    this.focus_handle(cx).focus(window);
+                                    this.focus_handle(cx).focus(window, cx);
                                 }))
                                 .on_mouse_down(
                                     MouseButton::Right,

crates/recent_projects/src/remote_connections.rs πŸ”—

@@ -209,7 +209,7 @@ impl RemoteConnectionPrompt {
         let markdown = cx.new(|cx| Markdown::new_text(prompt.into(), cx));
         self.prompt = Some((markdown, tx));
         self.status_message.take();
-        window.focus(&self.editor.focus_handle(cx));
+        window.focus(&self.editor.focus_handle(cx), cx);
         cx.notify();
     }
 

crates/recent_projects/src/remote_servers.rs πŸ”—

@@ -76,7 +76,7 @@ impl CreateRemoteServer {
     fn new(window: &mut Window, cx: &mut App) -> Self {
         let address_editor = cx.new(|cx| Editor::single_line(window, cx));
         address_editor.update(cx, |this, cx| {
-            this.focus_handle(cx).focus(window);
+            this.focus_handle(cx).focus(window, cx);
         });
         Self {
             address_editor,
@@ -107,7 +107,7 @@ struct CreateRemoteDevContainer {
 impl CreateRemoteDevContainer {
     fn new(window: &mut Window, cx: &mut Context<RemoteServerProjects>) -> Self {
         let entries = std::array::from_fn(|_| NavigableEntry::focusable(cx));
-        entries[0].focus_handle.focus(window);
+        entries[0].focus_handle.focus(window, cx);
         Self {
             entries,
             progress: DevContainerCreationProgress::Initial,
@@ -199,7 +199,7 @@ impl EditNicknameState {
                 this.set_text(starting_text, window, cx);
             }
         });
-        this.editor.focus_handle(cx).focus(window);
+        this.editor.focus_handle(cx).focus(window, cx);
         this
     }
 }
@@ -792,7 +792,7 @@ impl RemoteServerProjects {
                         this.retained_connections.push(client);
                         this.add_ssh_server(connection_options, cx);
                         this.mode = Mode::default_mode(&this.ssh_config_servers, cx);
-                        this.focus_handle(cx).focus(window);
+                        this.focus_handle(cx).focus(window, cx);
                         cx.notify()
                     })
                     .log_err(),
@@ -875,7 +875,7 @@ impl RemoteServerProjects {
 
                     crate::add_wsl_distro(fs, &connection_options, cx);
                     this.mode = Mode::default_mode(&BTreeSet::new(), cx);
-                    this.focus_handle(cx).focus(window);
+                    this.focus_handle(cx).focus(window, cx);
                     cx.notify();
                 }),
                 _ => this.update(cx, |this, cx| {
@@ -924,7 +924,7 @@ impl RemoteServerProjects {
                 return;
             }
         });
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
         cx.notify();
     }
 
@@ -933,7 +933,7 @@ impl RemoteServerProjects {
             CreateRemoteDevContainer::new(window, cx)
                 .progress(DevContainerCreationProgress::Creating),
         );
-        self.focus_handle(cx).focus(window);
+        self.focus_handle(cx).focus(window, cx);
         cx.notify();
     }
 
@@ -1068,7 +1068,7 @@ impl RemoteServerProjects {
                     }
                 });
                 self.mode = Mode::default_mode(&self.ssh_config_servers, cx);
-                self.focus_handle.focus(window);
+                self.focus_handle.focus(window, cx);
             }
             #[cfg(target_os = "windows")]
             Mode::AddWslDistro(state) => {
@@ -1094,7 +1094,7 @@ impl RemoteServerProjects {
             }
             _ => {
                 self.mode = Mode::default_mode(&self.ssh_config_servers, cx);
-                self.focus_handle(cx).focus(window);
+                self.focus_handle(cx).focus(window, cx);
                 cx.notify();
             }
         }
@@ -1640,7 +1640,7 @@ impl RemoteServerProjects {
     ) -> impl IntoElement {
         match &state.progress {
             DevContainerCreationProgress::Error(message) => {
-                self.focus_handle(cx).focus(window);
+                self.focus_handle(cx).focus(window, cx);
                 return div()
                     .track_focus(&self.focus_handle(cx))
                     .size_full()
@@ -1952,7 +1952,7 @@ impl RemoteServerProjects {
         let connection_prompt = state.connection_prompt.clone();
 
         state.picker.update(cx, |picker, cx| {
-            picker.focus_handle(cx).focus(window);
+            picker.focus_handle(cx).focus(window, cx);
         });
 
         v_flex()
@@ -2752,7 +2752,7 @@ impl Render for RemoteServerProjects {
             .on_action(cx.listener(Self::cancel))
             .on_action(cx.listener(Self::confirm))
             .capture_any_mouse_down(cx.listener(|this, _, window, cx| {
-                this.focus_handle(cx).focus(window);
+                this.focus_handle(cx).focus(window, cx);
             }))
             .on_mouse_down_out(cx.listener(|this, _, _, cx| {
                 if matches!(this.mode, Mode::Default(_)) {

crates/rules_library/src/rules_library.rs πŸ”—

@@ -720,7 +720,7 @@ impl RulesLibrary {
             if focus {
                 rule_editor
                     .body_editor
-                    .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx)));
+                    .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx), cx));
             }
             self.set_active_rule(Some(prompt_id), window, cx);
         } else if let Some(rule_metadata) = self.store.read(cx).metadata(prompt_id) {
@@ -763,7 +763,7 @@ impl RulesLibrary {
                             editor.set_current_line_highlight(Some(CurrentLineHighlight::None));
                             editor.set_completion_provider(Some(make_completion_provider()));
                             if focus {
-                                window.focus(&editor.focus_handle(cx));
+                                window.focus(&editor.focus_handle(cx), cx);
                             }
                             editor
                         });
@@ -939,7 +939,7 @@ impl RulesLibrary {
         if let Some(active_rule) = self.active_rule_id {
             self.rule_editors[&active_rule]
                 .body_editor
-                .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx)));
+                .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx), cx));
             cx.stop_propagation();
         }
     }
@@ -998,7 +998,7 @@ impl RulesLibrary {
         if let Some(rule_id) = self.active_rule_id
             && let Some(rule_editor) = self.rule_editors.get(&rule_id)
         {
-            window.focus(&rule_editor.body_editor.focus_handle(cx));
+            window.focus(&rule_editor.body_editor.focus_handle(cx), cx);
         }
     }
 
@@ -1011,7 +1011,7 @@ impl RulesLibrary {
         if let Some(rule_id) = self.active_rule_id
             && let Some(rule_editor) = self.rule_editors.get(&rule_id)
         {
-            window.focus(&rule_editor.title_editor.focus_handle(cx));
+            window.focus(&rule_editor.title_editor.focus_handle(cx), cx);
         }
     }
 
@@ -1308,8 +1308,8 @@ impl RulesLibrary {
                         .size_full()
                         .relative()
                         .overflow_hidden()
-                        .on_click(cx.listener(move |_, _, window, _| {
-                            window.focus(&focus_handle);
+                        .on_click(cx.listener(move |_, _, window, cx| {
+                            window.focus(&focus_handle, cx);
                         }))
                         .child(
                             h_flex()

crates/search/src/buffer_search.rs πŸ”—

@@ -518,7 +518,7 @@ impl BufferSearchBar {
 
     pub fn register(registrar: &mut impl SearchActionsRegistrar) {
         registrar.register_handler(ForDeployed(|this, _: &FocusSearch, window, cx| {
-            this.query_editor.focus_handle(cx).focus(window);
+            this.query_editor.focus_handle(cx).focus(window, cx);
             this.select_query(window, cx);
         }));
         registrar.register_handler(ForDeployed(
@@ -706,7 +706,7 @@ impl BufferSearchBar {
             active_editor.search_bar_visibility_changed(false, window, cx);
             active_editor.toggle_filtered_search_ranges(None, window, cx);
             let handle = active_editor.item_focus_handle(cx);
-            self.focus(&handle, window);
+            self.focus(&handle, window, cx);
         }
 
         cx.emit(Event::UpdateLocation);
@@ -749,7 +749,7 @@ impl BufferSearchBar {
                     self.select_query(window, cx);
                 }
 
-                window.focus(&handle);
+                window.focus(&handle, cx);
             }
             return true;
         }
@@ -878,7 +878,7 @@ impl BufferSearchBar {
     }
 
     pub fn focus_replace(&mut self, window: &mut Window, cx: &mut Context<Self>) {
-        self.focus(&self.replacement_editor.focus_handle(cx), window);
+        self.focus(&self.replacement_editor.focus_handle(cx), window, cx);
         cx.notify();
     }
 
@@ -909,7 +909,7 @@ impl BufferSearchBar {
     pub fn focus_editor(&mut self, _: &FocusEditor, window: &mut Window, cx: &mut Context<Self>) {
         if let Some(active_editor) = self.active_searchable_item.as_ref() {
             let handle = active_editor.item_focus_handle(cx);
-            window.focus(&handle);
+            window.focus(&handle, cx);
         }
     }
 
@@ -1384,7 +1384,7 @@ impl BufferSearchBar {
             Direction::Prev => (current_index - 1) % handles.len(),
         };
         let next_focus_handle = &handles[new_index];
-        self.focus(next_focus_handle, window);
+        self.focus(next_focus_handle, window, cx);
         cx.stop_propagation();
     }
 
@@ -1431,9 +1431,9 @@ impl BufferSearchBar {
         }
     }
 
-    fn focus(&self, handle: &gpui::FocusHandle, window: &mut Window) {
+    fn focus(&self, handle: &gpui::FocusHandle, window: &mut Window, cx: &mut App) {
         window.invalidate_character_coordinates();
-        window.focus(handle);
+        window.focus(handle, cx);
     }
 
     fn toggle_replace(&mut self, _: &ToggleReplace, window: &mut Window, cx: &mut Context<Self>) {
@@ -1444,7 +1444,7 @@ impl BufferSearchBar {
             } else {
                 self.query_editor.focus_handle(cx)
             };
-            self.focus(&handle, window);
+            self.focus(&handle, window, cx);
             cx.notify();
         }
     }
@@ -2038,7 +2038,7 @@ mod tests {
             .update(cx, |_, window, cx| {
                 search_bar.update(cx, |search_bar, cx| {
                     let handle = search_bar.query_editor.focus_handle(cx);
-                    window.focus(&handle);
+                    window.focus(&handle, cx);
                     search_bar.activate_current_match(window, cx);
                 });
                 assert!(
@@ -2056,7 +2056,7 @@ mod tests {
                 search_bar.update(cx, |search_bar, cx| {
                     assert_eq!(search_bar.active_match_index, Some(0));
                     let handle = search_bar.query_editor.focus_handle(cx);
-                    window.focus(&handle);
+                    window.focus(&handle, cx);
                     search_bar.select_all_matches(&SelectAllMatches, window, cx);
                 });
                 assert!(
@@ -2109,7 +2109,7 @@ mod tests {
                         "Match index should be updated to the next one"
                     );
                     let handle = search_bar.query_editor.focus_handle(cx);
-                    window.focus(&handle);
+                    window.focus(&handle, cx);
                     search_bar.select_all_matches(&SelectAllMatches, window, cx);
                 });
             })
@@ -2175,7 +2175,7 @@ mod tests {
             .update(cx, |_, window, cx| {
                 search_bar.update(cx, |search_bar, cx| {
                     let handle = search_bar.query_editor.focus_handle(cx);
-                    window.focus(&handle);
+                    window.focus(&handle, cx);
                     search_bar.search("abas_nonexistent_match", None, true, window, cx)
                 })
             })

crates/search/src/project_search.rs πŸ”—

@@ -954,9 +954,9 @@ impl ProjectSearchView {
             cx.on_next_frame(window, |this, window, cx| {
                 if this.focus_handle.is_focused(window) {
                     if this.has_matches() {
-                        this.results_editor.focus_handle(cx).focus(window);
+                        this.results_editor.focus_handle(cx).focus(window, cx);
                     } else {
-                        this.query_editor.focus_handle(cx).focus(window);
+                        this.query_editor.focus_handle(cx).focus(window, cx);
                     }
                 }
             });
@@ -1453,7 +1453,7 @@ impl ProjectSearchView {
             query_editor.select_all(&SelectAll, window, cx);
         });
         let editor_handle = self.query_editor.focus_handle(cx);
-        window.focus(&editor_handle);
+        window.focus(&editor_handle, cx);
     }
 
     fn set_query(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) {
@@ -1493,7 +1493,7 @@ impl ProjectSearchView {
             });
         });
         let results_handle = self.results_editor.focus_handle(cx);
-        window.focus(&results_handle);
+        window.focus(&results_handle, cx);
     }
 
     fn entity_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -1750,7 +1750,7 @@ impl ProjectSearchBar {
     fn focus_search(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         if let Some(search_view) = self.active_project_search.as_ref() {
             search_view.update(cx, |search_view, cx| {
-                search_view.query_editor.focus_handle(cx).focus(window);
+                search_view.query_editor.focus_handle(cx).focus(window, cx);
             });
         }
     }
@@ -1783,7 +1783,7 @@ impl ProjectSearchBar {
                 Direction::Prev => (current_index - 1) % views.len(),
             };
             let next_focus_handle = &views[new_index];
-            window.focus(next_focus_handle);
+            window.focus(next_focus_handle, cx);
             cx.stop_propagation();
         });
     }
@@ -1832,7 +1832,7 @@ impl ProjectSearchBar {
                 } else {
                     this.query_editor.focus_handle(cx)
                 };
-                window.focus(&editor_to_focus);
+                window.focus(&editor_to_focus, cx);
                 cx.notify();
             });
         }
@@ -4352,7 +4352,7 @@ pub mod tests {
         let buffer_search_query = "search bar query";
         buffer_search_bar
             .update_in(&mut cx, |buffer_search_bar, window, cx| {
-                buffer_search_bar.focus_handle(cx).focus(window);
+                buffer_search_bar.focus_handle(cx).focus(window, cx);
                 buffer_search_bar.search(buffer_search_query, None, true, window, cx)
             })
             .await

crates/search/src/search.rs πŸ”—

@@ -143,7 +143,7 @@ impl SearchOption {
                 let focus_handle = focus_handle.clone();
                 button.on_click(move |_: &ClickEvent, window, cx| {
                     if !focus_handle.is_focused(window) {
-                        window.focus(&focus_handle);
+                        window.focus(&focus_handle, cx);
                     }
                     window.dispatch_action(action.boxed_clone(), cx);
                 })

crates/search/src/search_bar.rs πŸ”—

@@ -27,7 +27,7 @@ pub(super) fn render_action_button(
         let focus_handle = focus_handle.clone();
         move |_, window, cx| {
             if !focus_handle.is_focused(window) {
-                window.focus(&focus_handle);
+                window.focus(&focus_handle, cx);
             }
             window.dispatch_action(action.boxed_clone(), cx);
         }

crates/settings_ui/src/settings_ui.rs πŸ”—

@@ -345,8 +345,8 @@ impl NonFocusableHandle {
     fn from_handle(handle: FocusHandle, window: &mut Window, cx: &mut App) -> Entity<Self> {
         cx.new(|cx| {
             let _subscription = cx.on_focus(&handle, window, {
-                move |_, window, _| {
-                    window.focus_next();
+                move |_, window, cx| {
+                    window.focus_next(cx);
                 }
             });
             Self {
@@ -1537,7 +1537,7 @@ impl SettingsWindow {
         this.build_search_index();
 
         this.search_bar.update(cx, |editor, cx| {
-            editor.focus_handle(cx).focus(window);
+            editor.focus_handle(cx).focus(window, cx);
         });
 
         this
@@ -2174,7 +2174,7 @@ impl SettingsWindow {
                     let focus_handle = focus_handle.clone();
                     move |this, _: &gpui::ClickEvent, window, cx| {
                         this.change_file(ix, window, cx);
-                        focus_handle.focus(window);
+                        focus_handle.focus(window, cx);
                     }
                 }))
             };
@@ -2251,7 +2251,7 @@ impl SettingsWindow {
                                                             this.update(cx, |this, cx| {
                                                                 this.change_file(ix, window, cx);
                                                             });
-                                                            focus_handle.focus(window);
+                                                            focus_handle.focus(window, cx);
                                                         }
                                                     },
                                                 );
@@ -2385,7 +2385,7 @@ impl SettingsWindow {
                 let focused_entry_parent = this.root_entry_containing(focused_entry);
                 if this.navbar_entries[focused_entry_parent].expanded {
                     this.toggle_navbar_entry(focused_entry_parent);
-                    window.focus(&this.navbar_entries[focused_entry_parent].focus_handle);
+                    window.focus(&this.navbar_entries[focused_entry_parent].focus_handle, cx);
                 }
                 cx.notify();
             }))
@@ -2534,6 +2534,7 @@ impl SettingsWindow {
                                                         window.focus(
                                                             &this.navbar_entries[entry_index]
                                                                 .focus_handle,
+                                                            cx,
                                                         );
                                                         cx.notify();
                                                     },
@@ -2658,7 +2659,7 @@ impl SettingsWindow {
         // back to back.
         cx.on_next_frame(window, move |_, window, cx| {
             if let Some(handle) = handle_to_focus.as_ref() {
-                window.focus(handle);
+                window.focus(handle, cx);
             }
 
             cx.on_next_frame(window, |_, _, cx| {
@@ -2725,7 +2726,7 @@ impl SettingsWindow {
         };
         self.navbar_scroll_handle
             .scroll_to_item(position, gpui::ScrollStrategy::Top);
-        window.focus(&self.navbar_entries[nav_entry_index].focus_handle);
+        window.focus(&self.navbar_entries[nav_entry_index].focus_handle, cx);
         cx.notify();
     }
 
@@ -3100,7 +3101,7 @@ impl SettingsWindow {
             .id("settings-ui-page")
             .on_action(cx.listener(|this, _: &menu::SelectNext, window, cx| {
                 if !sub_page_stack().is_empty() {
-                    window.focus_next();
+                    window.focus_next(cx);
                     return;
                 }
                 for (logical_index, (actual_index, _)) in this.visible_page_items().enumerate() {
@@ -3120,7 +3121,7 @@ impl SettingsWindow {
                         cx.on_next_frame(window, |_, window, cx| {
                             cx.notify();
                             cx.on_next_frame(window, |_, window, cx| {
-                                window.focus_next();
+                                window.focus_next(cx);
                                 cx.notify();
                             });
                         });
@@ -3128,11 +3129,11 @@ impl SettingsWindow {
                         return;
                     }
                 }
-                window.focus_next();
+                window.focus_next(cx);
             }))
             .on_action(cx.listener(|this, _: &menu::SelectPrevious, window, cx| {
                 if !sub_page_stack().is_empty() {
-                    window.focus_prev();
+                    window.focus_prev(cx);
                     return;
                 }
                 let mut prev_was_header = false;
@@ -3152,7 +3153,7 @@ impl SettingsWindow {
                         cx.on_next_frame(window, |_, window, cx| {
                             cx.notify();
                             cx.on_next_frame(window, |_, window, cx| {
-                                window.focus_prev();
+                                window.focus_prev(cx);
                                 cx.notify();
                             });
                         });
@@ -3161,7 +3162,7 @@ impl SettingsWindow {
                     }
                     prev_was_header = is_header;
                 }
-                window.focus_prev();
+                window.focus_prev(cx);
             }))
             .when(sub_page_stack().is_empty(), |this| {
                 this.vertical_scrollbar_for(&self.list_state, window, cx)
@@ -3364,19 +3365,19 @@ impl SettingsWindow {
         });
         self.sub_page_scroll_handle
             .set_offset(point(px(0.), px(0.)));
-        self.content_focus_handle.focus_handle(cx).focus(window);
+        self.content_focus_handle.focus_handle(cx).focus(window, cx);
         cx.notify();
     }
 
     fn pop_sub_page(&mut self, window: &mut Window, cx: &mut Context<SettingsWindow>) {
         sub_page_stack_mut().pop();
-        self.content_focus_handle.focus_handle(cx).focus(window);
+        self.content_focus_handle.focus_handle(cx).focus(window, cx);
         cx.notify();
     }
 
-    fn focus_file_at_index(&mut self, index: usize, window: &mut Window) {
+    fn focus_file_at_index(&mut self, index: usize, window: &mut Window, cx: &mut App) {
         if let Some((_, handle)) = self.files.get(index) {
-            handle.focus(window);
+            handle.focus(window, cx);
         }
     }
 
@@ -3456,7 +3457,7 @@ impl Render for SettingsWindow {
                             window.minimize_window();
                         })
                         .on_action(cx.listener(|this, _: &search::FocusSearch, window, cx| {
-                            this.search_bar.focus_handle(cx).focus(window);
+                            this.search_bar.focus_handle(cx).focus(window, cx);
                         }))
                         .on_action(cx.listener(|this, _: &ToggleFocusNav, window, cx| {
                             if this
@@ -3476,8 +3477,8 @@ impl Render for SettingsWindow {
                             }
                         }))
                         .on_action(cx.listener(
-                            |this, FocusFile(file_index): &FocusFile, window, _| {
-                                this.focus_file_at_index(*file_index as usize, window);
+                            |this, FocusFile(file_index): &FocusFile, window, cx| {
+                                this.focus_file_at_index(*file_index as usize, window, cx);
                             },
                         ))
                         .on_action(cx.listener(|this, _: &FocusNextFile, window, cx| {
@@ -3485,11 +3486,11 @@ impl Render for SettingsWindow {
                                 this.focused_file_index(window, cx) + 1,
                                 this.files.len().saturating_sub(1),
                             );
-                            this.focus_file_at_index(next_index, window);
+                            this.focus_file_at_index(next_index, window, cx);
                         }))
                         .on_action(cx.listener(|this, _: &FocusPreviousFile, window, cx| {
                             let prev_index = this.focused_file_index(window, cx).saturating_sub(1);
-                            this.focus_file_at_index(prev_index, window);
+                            this.focus_file_at_index(prev_index, window, cx);
                         }))
                         .on_action(cx.listener(|this, _: &menu::SelectNext, window, cx| {
                             if this
@@ -3499,11 +3500,11 @@ impl Render for SettingsWindow {
                             {
                                 this.focus_and_scroll_to_first_visible_nav_entry(window, cx);
                             } else {
-                                window.focus_next();
+                                window.focus_next(cx);
                             }
                         }))
-                        .on_action(|_: &menu::SelectPrevious, window, _| {
-                            window.focus_prev();
+                        .on_action(|_: &menu::SelectPrevious, window, cx| {
+                            window.focus_prev(cx);
                         })
                         .flex()
                         .flex_row()

crates/terminal_view/src/terminal_element.rs πŸ”—

@@ -632,7 +632,7 @@ impl TerminalElement {
     ) -> impl Fn(&E, &mut Window, &mut App) {
         move |event, window, cx| {
             if steal_focus {
-                window.focus(&focus_handle);
+                window.focus(&focus_handle, cx);
             } else if !focus_handle.is_focused(window) {
                 return;
             }
@@ -661,7 +661,7 @@ impl TerminalElement {
             let terminal_view = terminal_view.clone();
 
             move |e, window, cx| {
-                window.focus(&focus);
+                window.focus(&focus, cx);
 
                 let scroll_top = terminal_view.read(cx).scroll_top;
                 terminal.update(cx, |terminal, cx| {

crates/terminal_view/src/terminal_panel.rs πŸ”—

@@ -351,7 +351,7 @@ impl TerminalPanel {
                 } else if let Some(focus_on_pane) =
                     focus_on_pane.as_ref().or_else(|| self.center.panes().pop())
                 {
-                    focus_on_pane.focus_handle(cx).focus(window);
+                    focus_on_pane.focus_handle(cx).focus(window, cx);
                 }
             }
             pane::Event::ZoomIn => {
@@ -397,7 +397,7 @@ impl TerminalPanel {
                                     .center
                                     .split(&pane, &new_pane, direction, cx)
                                     .log_err();
-                                window.focus(&new_pane.focus_handle(cx));
+                                window.focus(&new_pane.focus_handle(cx), cx);
                             })
                             .ok();
                     })
@@ -419,7 +419,7 @@ impl TerminalPanel {
                         pane.add_item(item, true, true, None, window, cx);
                     });
                     self.center.split(&pane, &new_pane, direction, cx).log_err();
-                    window.focus(&new_pane.focus_handle(cx));
+                    window.focus(&new_pane.focus_handle(cx), cx);
                 }
             }
             pane::Event::Focus => {
@@ -998,7 +998,7 @@ impl TerminalPanel {
                 RevealStrategy::NoFocus => match reveal_target {
                     RevealTarget::Center => {
                         task_workspace.update_in(cx, |workspace, window, cx| {
-                            workspace.active_pane().focus_handle(cx).focus(window);
+                            workspace.active_pane().focus_handle(cx).focus(window, cx);
                         })?;
                     }
                     RevealTarget::Dock => {
@@ -1053,7 +1053,7 @@ impl TerminalPanel {
             .center
             .find_pane_in_direction(&self.active_pane, direction, cx)
         {
-            window.focus(&pane.focus_handle(cx));
+            window.focus(&pane.focus_handle(cx), cx);
         } else {
             self.workspace
                 .update(cx, |workspace, cx| {
@@ -1297,7 +1297,7 @@ fn add_paths_to_terminal(
         .active_item()
         .and_then(|item| item.downcast::<TerminalView>())
     {
-        window.focus(&terminal_view.focus_handle(cx));
+        window.focus(&terminal_view.focus_handle(cx), cx);
         let mut new_text = paths.iter().map(|path| format!(" {path:?}")).join("");
         new_text.push(' ');
         terminal_view.update(cx, |terminal_view, cx| {
@@ -1451,7 +1451,7 @@ impl Render for TerminalPanel {
                             .position(|pane| **pane == terminal_panel.active_pane)
                         {
                             let next_ix = (ix + 1) % panes.len();
-                            window.focus(&panes[next_ix].focus_handle(cx));
+                            window.focus(&panes[next_ix].focus_handle(cx), cx);
                         }
                     }),
                 )
@@ -1463,7 +1463,7 @@ impl Render for TerminalPanel {
                             .position(|pane| **pane == terminal_panel.active_pane)
                         {
                             let prev_ix = cmp::min(ix.wrapping_sub(1), panes.len() - 1);
-                            window.focus(&panes[prev_ix].focus_handle(cx));
+                            window.focus(&panes[prev_ix].focus_handle(cx), cx);
                         }
                     },
                 ))
@@ -1471,7 +1471,7 @@ impl Render for TerminalPanel {
                     cx.listener(|terminal_panel, action: &ActivatePane, window, cx| {
                         let panes = terminal_panel.center.panes();
                         if let Some(&pane) = panes.get(action.0) {
-                            window.focus(&pane.read(cx).focus_handle(cx));
+                            window.focus(&pane.read(cx).focus_handle(cx), cx);
                         } else {
                             let future =
                                 terminal_panel.new_pane_with_cloned_active_terminal(window, cx);
@@ -1490,7 +1490,7 @@ impl Render for TerminalPanel {
                                                 )
                                                 .log_err();
                                             let new_pane = new_pane.read(cx);
-                                            window.focus(&new_pane.focus_handle(cx));
+                                            window.focus(&new_pane.focus_handle(cx), cx);
                                         },
                                     );
                                 }

crates/terminal_view/src/terminal_view.rs πŸ”—

@@ -409,7 +409,7 @@ impl TerminalView {
                 )
         });
 
-        window.focus(&context_menu.focus_handle(cx));
+        window.focus(&context_menu.focus_handle(cx), cx);
         let subscription = cx.subscribe_in(
             &context_menu,
             window,

crates/title_bar/src/title_bar.rs πŸ”—

@@ -605,7 +605,7 @@ impl TitleBar {
                 })
                 .on_click(move |_, window, cx| {
                     let _ = workspace.update(cx, |this, cx| {
-                        window.focus(&this.active_pane().focus_handle(cx));
+                        window.focus(&this.active_pane().focus_handle(cx), cx);
                         window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx);
                     });
                 })

crates/toolchain_selector/src/toolchain_selector.rs πŸ”—

@@ -225,7 +225,7 @@ impl AddToolchainState {
                                 );
                             });
                             *input_state = Self::wait_for_path(rx, window, cx);
-                            this.focus_handle(cx).focus(window);
+                            this.focus_handle(cx).focus(window, cx);
                         }
                     });
                     return Err(anyhow::anyhow!("Failed to resolve toolchain"));
@@ -260,7 +260,7 @@ impl AddToolchainState {
                         toolchain,
                         scope_picker,
                     };
-                    this.focus_handle(cx).focus(window);
+                    this.focus_handle(cx).focus(window, cx);
                 });
 
                 Result::<_, anyhow::Error>::Ok(())
@@ -333,7 +333,7 @@ impl AddToolchainState {
         });
         _ = self.weak.update(cx, |this, cx| {
             this.state = State::Search((this.create_search_state)(window, cx));
-            this.focus_handle(cx).focus(window);
+            this.focus_handle(cx).focus(window, cx);
             cx.notify();
         });
     }
@@ -383,7 +383,7 @@ impl Render for AddToolchainState {
                     &weak,
                     |this: &mut ToolchainSelector, _: &menu::Cancel, window, cx| {
                         this.state = State::Search((this.create_search_state)(window, cx));
-                        this.state.focus_handle(cx).focus(window);
+                        this.state.focus_handle(cx).focus(window, cx);
                         cx.notify();
                     },
                 ))
@@ -703,7 +703,7 @@ impl ToolchainSelector {
                 window,
                 cx,
             ));
-            self.state.focus_handle(cx).focus(window);
+            self.state.focus_handle(cx).focus(window, cx);
             cx.notify();
         }
     }

crates/ui/src/components/context_menu.rs πŸ”—

@@ -562,7 +562,7 @@ impl ContextMenu {
             action: Some(action.boxed_clone()),
             handler: Rc::new(move |context, window, cx| {
                 if let Some(context) = &context {
-                    window.focus(context);
+                    window.focus(context, cx);
                 }
                 window.dispatch_action(action.boxed_clone(), cx);
             }),
@@ -594,7 +594,7 @@ impl ContextMenu {
             action: Some(action.boxed_clone()),
             handler: Rc::new(move |context, window, cx| {
                 if let Some(context) = &context {
-                    window.focus(context);
+                    window.focus(context, cx);
                 }
                 window.dispatch_action(action.boxed_clone(), cx);
             }),

crates/ui/src/components/navigable.rs πŸ”—

@@ -75,7 +75,7 @@ impl RenderOnce for Navigable {
                         })
                         .unwrap_or(0);
                     if let Some(entry) = children.get(target) {
-                        entry.focus_handle.focus(window);
+                        entry.focus_handle.focus(window, cx);
                         if let Some(anchor) = &entry.scroll_anchor {
                             anchor.scroll_to(window, cx);
                         }
@@ -89,7 +89,7 @@ impl RenderOnce for Navigable {
                         .and_then(|index| index.checked_sub(1))
                         .or(children.len().checked_sub(1));
                     if let Some(entry) = target.and_then(|target| children.get(target)) {
-                        entry.focus_handle.focus(window);
+                        entry.focus_handle.focus(window, cx);
                         if let Some(anchor) = &entry.scroll_anchor {
                             anchor.scroll_to(window, cx);
                         }

crates/ui/src/components/popover_menu.rs πŸ”—

@@ -281,7 +281,7 @@ fn show_menu<M: ManagedView>(
             if modal.focus_handle(cx).contains_focused(window, cx)
                 && let Some(previous_focus_handle) = previous_focus_handle.as_ref()
             {
-                window.focus(previous_focus_handle);
+                window.focus(previous_focus_handle, cx);
             }
             *menu2.borrow_mut() = None;
             window.refresh();
@@ -296,8 +296,8 @@ fn show_menu<M: ManagedView>(
     // flickering when opening popover menus.
     let focus_handle = new_menu.focus_handle(cx);
     window.on_next_frame(move |window, _cx| {
-        window.on_next_frame(move |window, _cx| {
-            window.focus(&focus_handle);
+        window.on_next_frame(move |window, cx| {
+            window.focus(&focus_handle, cx);
         });
     });
     *menu.borrow_mut() = Some(new_menu);

crates/ui/src/components/right_click_menu.rs πŸ”—

@@ -253,7 +253,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
                                     && let Some(previous_focus_handle) =
                                         previous_focus_handle.as_ref()
                                 {
-                                    window.focus(previous_focus_handle);
+                                    window.focus(previous_focus_handle, cx);
                                 }
                                 *menu2.borrow_mut() = None;
                                 window.refresh();
@@ -268,8 +268,8 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
                         // flickering when opening menus.
                         let focus_handle = new_menu.focus_handle(cx);
                         window.on_next_frame(move |window, _cx| {
-                            window.on_next_frame(move |window, _cx| {
-                                window.focus(&focus_handle);
+                            window.on_next_frame(move |window, cx| {
+                                window.focus(&focus_handle, cx);
                             });
                         });
                         *menu.borrow_mut() = Some(new_menu);

crates/ui_input/src/number_field.rs πŸ”—

@@ -476,7 +476,7 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
                                                         if let Some(previous) =
                                                             previous_focus_handle.as_ref()
                                                         {
-                                                            window.focus(previous);
+                                                            window.focus(previous, cx);
                                                         }
                                                         on_change(&new_value, window, cx);
                                                     };
@@ -485,7 +485,7 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
                                             })
                                             .detach();
 
-                                            window.focus(&editor.focus_handle(cx));
+                                            window.focus(&editor.focus_handle(cx), cx);
 
                                             editor
                                         }

crates/workspace/src/dock.rs πŸ”—

@@ -350,7 +350,7 @@ impl Dock {
             let focus_subscription =
                 cx.on_focus(&focus_handle, window, |dock: &mut Dock, window, cx| {
                     if let Some(active_entry) = dock.active_panel_entry() {
-                        active_entry.panel.panel_focus_handle(cx).focus(window)
+                        active_entry.panel.panel_focus_handle(cx).focus(window, cx)
                     }
                 });
             let zoom_subscription = cx.subscribe(&workspace, |dock, workspace, e: &Event, cx| {
@@ -593,7 +593,7 @@ impl Dock {
                         this.set_panel_zoomed(&panel.to_any(), true, window, cx);
                         if !PanelHandle::panel_focus_handle(panel, cx).contains_focused(window, cx)
                         {
-                            window.focus(&panel.focus_handle(cx));
+                            window.focus(&panel.focus_handle(cx), cx);
                         }
                         workspace
                             .update(cx, |workspace, cx| {
@@ -625,7 +625,7 @@ impl Dock {
                         {
                             this.set_open(true, window, cx);
                             this.activate_panel(ix, window, cx);
-                            window.focus(&panel.read(cx).focus_handle(cx));
+                            window.focus(&panel.read(cx).focus_handle(cx), cx);
                         }
                     }
                     PanelEvent::Close => {
@@ -1052,7 +1052,7 @@ impl Render for PanelButtons {
                                             name = name,
                                             toggle_state = !is_open
                                         );
-                                        window.focus(&focus_handle);
+                                        window.focus(&focus_handle, cx);
                                         window.dispatch_action(action.boxed_clone(), cx)
                                     }
                                 })

crates/workspace/src/item.rs πŸ”—

@@ -1042,7 +1042,7 @@ impl<T: Item> ItemHandle for Entity<T> {
 
     fn relay_action(&self, action: Box<dyn Action>, window: &mut Window, cx: &mut App) {
         self.update(cx, |this, cx| {
-            this.focus_handle(cx).focus(window);
+            this.focus_handle(cx).focus(window, cx);
             window.dispatch_action(action, cx);
         })
     }

crates/workspace/src/modal_layer.rs πŸ”—

@@ -116,7 +116,7 @@ impl ModalLayer {
             focus_handle,
         });
         cx.defer_in(window, move |_, window, cx| {
-            window.focus(&new_modal.focus_handle(cx));
+            window.focus(&new_modal.focus_handle(cx), cx);
         });
         cx.notify();
     }
@@ -144,7 +144,7 @@ impl ModalLayer {
             if let Some(previous_focus) = active_modal.previous_focus_handle
                 && active_modal.focus_handle.contains_focused(window, cx)
             {
-                previous_focus.focus(window);
+                previous_focus.focus(window, cx);
             }
             cx.notify();
         }

crates/workspace/src/pane.rs πŸ”—

@@ -625,11 +625,11 @@ impl Pane {
                     self.last_focus_handle_by_item.get(&active_item.item_id())
                     && let Some(focus_handle) = weak_last_focus_handle.upgrade()
                 {
-                    focus_handle.focus(window);
+                    focus_handle.focus(window, cx);
                     return;
                 }
 
-                active_item.item_focus_handle(cx).focus(window);
+                active_item.item_focus_handle(cx).focus(window, cx);
             } else if let Some(focused) = window.focused(cx)
                 && !self.context_menu_focused(window, cx)
             {
@@ -638,7 +638,7 @@ impl Pane {
             }
         } else if let Some(welcome_page) = self.welcome_page.as_ref() {
             if self.focus_handle.is_focused(window) {
-                welcome_page.read(cx).focus_handle(cx).focus(window);
+                welcome_page.read(cx).focus_handle(cx).focus(window, cx);
             }
         }
     }
@@ -1999,7 +1999,7 @@ impl Pane {
 
             let should_activate = activate_pane || self.has_focus(window, cx);
             if self.items.len() == 1 && should_activate {
-                self.focus_handle.focus(window);
+                self.focus_handle.focus(window, cx);
             } else {
                 self.activate_item(
                     index_to_activate,
@@ -2350,7 +2350,7 @@ impl Pane {
     pub fn focus_active_item(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         if let Some(active_item) = self.active_item() {
             let focus_handle = active_item.item_focus_handle(cx);
-            window.focus(&focus_handle);
+            window.focus(&focus_handle, cx);
         }
     }
 

crates/workspace/src/welcome.rs πŸ”—

@@ -250,12 +250,12 @@ impl WelcomePage {
     }
 
     fn select_next(&mut self, _: &SelectNext, window: &mut Window, cx: &mut Context<Self>) {
-        window.focus_next();
+        window.focus_next(cx);
         cx.notify();
     }
 
     fn select_previous(&mut self, _: &SelectPrevious, window: &mut Window, cx: &mut Context<Self>) {
-        window.focus_prev();
+        window.focus_prev(cx);
         cx.notify();
     }
 

crates/workspace/src/workspace.rs πŸ”—

@@ -1393,7 +1393,7 @@ impl Workspace {
 
         cx.on_focus_lost(window, |this, window, cx| {
             let focus_handle = this.focus_handle(cx);
-            window.focus(&focus_handle);
+            window.focus(&focus_handle, cx);
         })
         .detach();
 
@@ -1417,7 +1417,7 @@ impl Workspace {
         cx.subscribe_in(&center_pane, window, Self::handle_pane_event)
             .detach();
 
-        window.focus(&center_pane.focus_handle(cx));
+        window.focus(&center_pane.focus_handle(cx), cx);
 
         cx.emit(Event::PaneAdded(center_pane.clone()));
 
@@ -2057,7 +2057,7 @@ impl Workspace {
     ) -> Task<Result<()>> {
         let to_load = if let Some(pane) = pane.upgrade() {
             pane.update(cx, |pane, cx| {
-                window.focus(&pane.focus_handle(cx));
+                window.focus(&pane.focus_handle(cx), cx);
                 loop {
                     // Retrieve the weak item handle from the history.
                     let entry = pane.nav_history_mut().pop(mode, cx)?;
@@ -3176,7 +3176,7 @@ impl Workspace {
                     }
                 } else {
                     let focus_handle = &active_panel.panel_focus_handle(cx);
-                    window.focus(focus_handle);
+                    window.focus(focus_handle, cx);
                     reveal_dock = true;
                 }
             }
@@ -3188,7 +3188,7 @@ impl Workspace {
 
         if focus_center {
             self.active_pane
-                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)))
+                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx))
         }
 
         cx.notify();
@@ -3356,7 +3356,7 @@ impl Workspace {
                     if let Some(panel) = panel.as_ref() {
                         if should_focus(&**panel, window, cx) {
                             dock.set_open(true, window, cx);
-                            panel.panel_focus_handle(cx).focus(window);
+                            panel.panel_focus_handle(cx).focus(window, cx);
                         } else {
                             focus_center = true;
                         }
@@ -3366,7 +3366,7 @@ impl Workspace {
 
                 if focus_center {
                     self.active_pane
-                        .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)))
+                        .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx))
                 }
 
                 result_panel = panel;
@@ -3440,7 +3440,7 @@ impl Workspace {
 
         if focus_center {
             self.active_pane
-                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)))
+                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx))
         }
 
         if self.zoomed_position != dock_to_reveal {
@@ -3471,7 +3471,7 @@ impl Workspace {
             .detach();
         self.panes.push(pane.clone());
 
-        window.focus(&pane.focus_handle(cx));
+        window.focus(&pane.focus_handle(cx), cx);
 
         cx.emit(Event::PaneAdded(pane.clone()));
         pane
@@ -3866,7 +3866,7 @@ impl Workspace {
     ) {
         let panes = self.center.panes();
         if let Some(pane) = panes.get(action.0).map(|p| (*p).clone()) {
-            window.focus(&pane.focus_handle(cx));
+            window.focus(&pane.focus_handle(cx), cx);
         } else {
             self.split_and_clone(self.active_pane.clone(), SplitDirection::Right, window, cx)
                 .detach();
@@ -3936,7 +3936,7 @@ impl Workspace {
         if let Some(ix) = panes.iter().position(|pane| **pane == self.active_pane) {
             let next_ix = (ix + 1) % panes.len();
             let next_pane = panes[next_ix].clone();
-            window.focus(&next_pane.focus_handle(cx));
+            window.focus(&next_pane.focus_handle(cx), cx);
         }
     }
 
@@ -3945,7 +3945,7 @@ impl Workspace {
         if let Some(ix) = panes.iter().position(|pane| **pane == self.active_pane) {
             let prev_ix = cmp::min(ix.wrapping_sub(1), panes.len() - 1);
             let prev_pane = panes[prev_ix].clone();
-            window.focus(&prev_pane.focus_handle(cx));
+            window.focus(&prev_pane.focus_handle(cx), cx);
         }
     }
 
@@ -4041,7 +4041,7 @@ impl Workspace {
             Some(ActivateInDirectionTarget::Pane(pane)) => {
                 let pane = pane.read(cx);
                 if let Some(item) = pane.active_item() {
-                    item.item_focus_handle(cx).focus(window);
+                    item.item_focus_handle(cx).focus(window, cx);
                 } else {
                     log::error!(
                         "Could not find a focus target when in switching focus in {direction} direction for a pane",
@@ -4053,7 +4053,7 @@ impl Workspace {
                 window.defer(cx, move |window, cx| {
                     let dock = dock.read(cx);
                     if let Some(panel) = dock.active_panel() {
-                        panel.panel_focus_handle(cx).focus(window);
+                        panel.panel_focus_handle(cx).focus(window, cx);
                     } else {
                         log::error!("Could not find a focus target when in switching focus in {direction} direction for a {:?} dock", dock.position());
                     }
@@ -4673,7 +4673,7 @@ impl Workspace {
 
         // if you're already following, find the right pane and focus it.
         if let Some(follower_state) = self.follower_states.get(&leader_id) {
-            window.focus(&follower_state.pane().focus_handle(cx));
+            window.focus(&follower_state.pane().focus_handle(cx), cx);
 
             return;
         }
@@ -5485,12 +5485,12 @@ impl Workspace {
     ) {
         self.panes.retain(|p| p != pane);
         if let Some(focus_on) = focus_on {
-            focus_on.update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)));
+            focus_on.update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx));
         } else if self.active_pane() == pane {
             self.panes
                 .last()
                 .unwrap()
-                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)));
+                .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx));
         }
         if self.last_active_center_pane == Some(pane.downgrade()) {
             self.last_active_center_pane = None;
@@ -6248,7 +6248,7 @@ impl Workspace {
         let workspace = Self::new(Default::default(), project, app_state, window, cx);
         workspace
             .active_pane
-            .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx)));
+            .update(cx, |pane, cx| window.focus(&pane.focus_handle(cx), cx));
         workspace
     }
 
@@ -8722,7 +8722,7 @@ fn move_all_items(
         // This automatically removes duplicate items in the pane
         to_pane.update(cx, |destination, cx| {
             destination.add_item(item_handle, true, true, None, window, cx);
-            window.focus(&destination.focus_handle(cx))
+            window.focus(&destination.focus_handle(cx), cx)
         });
     }
 }
@@ -8766,7 +8766,7 @@ pub fn move_item(
             cx,
         );
         if activate {
-            window.focus(&destination.focus_handle(cx))
+            window.focus(&destination.focus_handle(cx), cx)
         }
     });
 }

crates/zed/src/main.rs πŸ”—

@@ -819,7 +819,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
                         workspace::get_any_active_workspace(app_state, cx.clone()).await?;
                     workspace.update(cx, |workspace, window, cx| {
                         if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
-                            panel.focus_handle(cx).focus(window);
+                            panel.focus_handle(cx).focus(window, cx);
                         }
                     })
                 })

crates/zed/src/zed.rs πŸ”—

@@ -477,7 +477,7 @@ pub fn initialize_workspace(
         initialize_panels(prompt_builder.clone(), window, cx);
         register_actions(app_state.clone(), workspace, window, cx);
 
-        workspace.focus_handle(cx).focus(window);
+        workspace.focus_handle(cx).focus(window, cx);
     })
     .detach();
 }

crates/zed/src/zed/component_preview.rs πŸ”—

@@ -161,7 +161,7 @@ impl ComponentPreview {
         component_preview.update_component_list(cx);
 
         let focus_handle = component_preview.filter_editor.read(cx).focus_handle(cx);
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
 
         Ok(component_preview)
     }
@@ -770,7 +770,7 @@ impl Item for ComponentPreview {
         self.workspace_id = workspace.database_id();
 
         let focus_handle = self.filter_editor.read(cx).focus_handle(cx);
-        window.focus(&focus_handle);
+        window.focus(&focus_handle, cx);
     }
 }