From 4037fc5a9203d78abb3e9327871f5a0eb7394e37 Mon Sep 17 00:00:00 2001 From: temportalflux Date: Sat, 6 Jun 2026 12:56:47 -0400 Subject: [PATCH] rework InputState::cursor_visible to be more clear that its a mutation during paint --- crates/gpui_elements/src/input/paint.rs | 9 +++-- crates/gpui_elements/src/input/state.rs | 44 ++++++++++++++----------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/crates/gpui_elements/src/input/paint.rs b/crates/gpui_elements/src/input/paint.rs index 7c3fad8f06..2bf64d13f8 100644 --- a/crates/gpui_elements/src/input/paint.rs +++ b/crates/gpui_elements/src/input/paint.rs @@ -139,10 +139,9 @@ impl Element for Input { let is_focused = focus_handle.is_focused(window); let colors = self.colors; - // TODO: refactor cursor_visible so it is clear that it is called on_paint - let cursor_visible = self - .input - .update(cx, |input, cx| input.cursor_visible(is_focused, cx)); + let is_cursor_visible = self.input.update(cx, |input, cx| { + input.toggle_cursor_on_focus_change(is_focused, cx) + }); let perform_paint = |_style: &Style, window: &mut Window, cx: &mut App| { let precomputed_first_line = match (snapshot.layout, snapshot.line_layouts.first()) { @@ -166,7 +165,7 @@ impl Element for Input { text_style: &text_style, placeholder: placeholder.as_ref(), colors: &colors, - cursor_visible, + cursor_visible: is_cursor_visible, precomputed_first_line, }; context.process_mouse_events(&self.input, window, cx); diff --git a/crates/gpui_elements/src/input/state.rs b/crates/gpui_elements/src/input/state.rs index 41e27f241a..0a9a3bbf7b 100644 --- a/crates/gpui_elements/src/input/state.rs +++ b/crates/gpui_elements/src/input/state.rs @@ -1,5 +1,5 @@ use super::actions::*; -use crate::input::{InputLayout, unicode::UnicodeString}; +use crate::input::{CursorBlink, InputLayout, unicode::UnicodeString}; use gpui::{ App, AppContext, ClipboardItem, Context, Entity, EntityId, EntityInputHandler, EventEmitter, FocusHandle, Focusable, Pixels, Point, SharedString, Subscription, TextRun, TextStyle, Window, @@ -151,27 +151,33 @@ impl InputState { self } - /// Returns whether the cursor should be visible (for blinking). - /// - /// If blinking is not enabled, always returns `true`. - /// This method also updates the blink manager's enabled state based on focus. - pub fn cursor_visible(&mut self, is_focused: bool, cx: &mut Context) -> bool { + /// Processes a focus-flag update during window paint, returning whether the cursor should be visible in this frame. + /// Returns false if the cursor is blinking and not currently visible. + pub(super) fn toggle_cursor_on_focus_change( + &mut self, + is_focused: bool, + cx: &mut Context, + ) -> bool { // Update cursor blink based on focus changes - if let Some((cursor_blink, _)) = &self.cursor_blink { - if is_focused && !self.was_focused { - cursor_blink.update(cx, |cb, cx| cb.enable(cx)); - cx.emit(InputStateEvent::Focus); - } else if !is_focused && self.was_focused { - cursor_blink.update(cx, |cb, cx| cb.disable(cx)); - cx.emit(InputStateEvent::Blur); - } - } + let was_focused = self.was_focused; self.was_focused = is_focused; - self.cursor_blink - .as_ref() - .map(|(cb, _)| cb.read(cx).visible()) - .unwrap_or(true) + match &self.cursor_blink { + None => true, + Some((cursor_blink, _)) => match (is_focused, was_focused) { + (true, false) => { + cursor_blink.update(cx, |cursor, cx| cursor.enable(cx)); + cx.emit(InputStateEvent::Focus); + true + } + (false, true) => { + cursor_blink.update(cx, |cursor, cx| cursor.disable(cx)); + cx.emit(InputStateEvent::Blur); + false + } + _ => cursor_blink.read(cx).visible(), + }, + } } /// Pauses cursor blinking temporarily (e.g., during typing).