From 5b85565d93c97ffa4faf7808e75737bc9f307345 Mon Sep 17 00:00:00 2001 From: Pavel Olizko <71591964+nolight132@users.noreply.github.com> Date: Mon, 17 Aug 2026 07:20:20 +0000 Subject: [PATCH] gpui: Make inactive frame throttling configurable (#62628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective I am building an [app](https://github.com/nolight132/sonora) with GPUI, and the current animation throttling implementation does not quite meet its requirements. I needed the window to stay at a smooth framerate when unfocused to display lyrics, which was not possible at the time without modifying GPUI’s frame scheduling behavior. I understand that this is not a problem for Zed, but I believe making this behavior a field in `WindowOptions` could be beneficial for other programs going forward. ## Solution Added a field to `WindowOptions` struct which controls the minimum interval between animation frames while the window is inactive (documented). Kept the default value GPUI currently uses. ## Testing - Ran `gpui/src/examples/animation.rs` with different presets - works as expected. Zed compiles. One thing worth noting: this setting does not guarantee the window refreshes at this exact interval, as frames are still paced by the compositor. For granular FPS control, a helper function is needed. I have decided to keep it simple and use the existing logic. - Tested on NixOS x86_64, Niri. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior (the default didn't change, tests still pass) - [x] Performance impact has been considered and is acceptable (no performance impact unless explicitly set) ## Showcase Before (unfocused): image After (unfocused with `inactive_frame_interval` set to 16ms): image --- Release Notes: - Added `WindowOptions::inactive_frame_interval` for configuring animation frame throttling on inactive GPUI windows. --- crates/gpui/src/platform.rs | 6 ++++++ crates/gpui/src/window.rs | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 805ed375ce..ecb1fa40d3 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -1827,6 +1827,11 @@ pub struct WindowOptions { /// Leave this `false` for windows that rely on AppKit's native titlebar dragging. pub app_owns_titlebar_drag: bool, + /// The minimum interval between animation frames while the window is inactive. + /// + /// Set to `None` to disable inactive-window animation frame throttling. + pub inactive_frame_interval: Option, + /// Whether the window should be resizable by the user pub is_resizable: bool, @@ -1971,6 +1976,7 @@ impl Default for WindowOptions { kind: WindowKind::Normal, is_movable: true, app_owns_titlebar_drag: false, + inactive_frame_interval: Some(Duration::from_micros(33_333)), is_resizable: true, is_minimizable: true, display_id: None, diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index a92ae8f8ef..4e2f11b75c 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1340,6 +1340,7 @@ impl Window { kind, is_movable, app_owns_titlebar_drag, + inactive_frame_interval, is_resizable, is_minimizable, display_id, @@ -1557,7 +1558,7 @@ impl Window { { None } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() { - Some(Duration::from_micros(33333)) + inactive_frame_interval } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state { Some(Duration::from_micros(16667)) } else {