editor: Blink cursors only in the focused editor (#61086)
Every editor associated with a window observed window activation. The handler enabled the blink manager for every editor, including hidden and unfocused editors. Their independent 500 ms timers invalidated the window out of phase and caused redundant full-window presents. Window activation and deactivation are already represented as focus transitions by GPUI: an inactive window has an empty effective focus path. Remove the redundant activation observer and rely on the editor focus and blur handlers to stop blinking on deactivation and restart it only for the editor that owns focus on activation. In a 40-second idle diagnostic run before this change, the steady-state tail repeatedly contained invalidations from one or two editors per frame. After the change, no unfocused-editor invalidations appeared. Bounded scrollbar fades and visible activity animations remain unchanged. Add a regression test with focused and unfocused editors that covers activation, deactivation, and reactivation. Release Notes: - Fixed cursors blinking in unfocused editors, reducing idle redraws. --------- Signed-off-by: Daan De Meyer <daan@amutable.com>
This commit is contained in:
1 parent
003decdcf8
commit
7eaddbc5d9
3 files changed
+44
-10
No files matched your search
@@ -112,4 +112,9 @@ impl BlinkManager {
|
||||
pub fn visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
@@ -2416,16 +2416,6 @@ impl Editor {
|
||||
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
|
||||
cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
|
||||
observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
|
||||
cx.observe_window_activation(window, |editor, window, cx| {
|
||||
let active = window.is_window_active();
|
||||
editor.blink_manager.update(cx, |blink_manager, cx| {
|
||||
if active {
|
||||
blink_manager.enable(cx);
|
||||
} else {
|
||||
blink_manager.disable(cx);
|
||||
}
|
||||
});
|
||||
}),
|
||||
]
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
|
||||
@@ -2485,6 +2485,45 @@ fn test_beginning_of_line_single_line_editor(cx: &mut TestAppContext) {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_only_focused_editor_blinks_across_window_activation(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let window = cx.add_window(|window, cx| Editor::single_line(window, cx));
|
||||
let unfocused_editor = window
|
||||
.update(cx, |focused_editor, window, cx| {
|
||||
window.focus(&focused_editor.focus_handle(cx), cx);
|
||||
let unfocused_editor = cx.new(|cx| Editor::single_line(window, cx));
|
||||
window.activate_window();
|
||||
unfocused_editor
|
||||
})
|
||||
.unwrap();
|
||||
let focused_editor = window.root(cx).unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*window, cx);
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update(|window, cx| {
|
||||
assert!(window.is_window_active());
|
||||
assert!(focused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
assert!(!unfocused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
});
|
||||
|
||||
cx.deactivate_window();
|
||||
cx.update(|window, cx| {
|
||||
assert!(!window.is_window_active());
|
||||
assert!(!focused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
assert!(!unfocused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
});
|
||||
|
||||
cx.update(|window, _| window.activate_window());
|
||||
cx.run_until_parked();
|
||||
cx.update(|window, cx| {
|
||||
assert!(window.is_window_active());
|
||||
assert!(focused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
assert!(!unfocused_editor.read(cx).blink_manager.read(cx).enabled());
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
Reference in new issue
Block a user