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):
After (unfocused with `inactive_frame_interval` set to 16ms):
---
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 {