Skip to content

Port medium-priority GPUI animation, LineLayout, and Windows Restart Manager APIs - #9

Merged
freefcw merged 3 commits into
develop/0.9from
cursor/zed-gpui-medium-ports-81de
Aug 29, 2026
Merged

Port medium-priority GPUI animation, LineLayout, and Windows Restart Manager APIs#9
freefcw merged 3 commits into
develop/0.9from
cursor/zed-gpui-medium-ports-81de

Conversation

@freefcw

@freefcw freefcw commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Three independent medium-priority Zed GPUI ports. Not a wholesale sync. One commit per topic.

Rebased onto develop/0.9 at 2ce2baf01d0efea99b0efea1471248539cc8a232 (merged #3).

Topics

1. Spring animations + animation max FPS + configurable inactive-window FPS

Local commit: 23f861f1c6ad2bf4fac462da23c12c02f1377b9c

  • Springs: SpringConfig / SpringAnimation / AnimationExt::with_spring (analytic step, retarget-preserving velocity).
  • Animation::with_max_fps schedules timer-driven redraws instead of every vsync.
  • WindowOptions::inactive_frame_interval (default still ~30 FPS; None disables the throttle). Useful for overlay/HUD/daemon windows.

Zed-Origin:

  • 8b1497dbd22fb06f5838a7c0b84a1e54fafa71bc (#62778)
  • dd04a229dd22700ff43815b8514453e197c333b7 (#62579)
  • 511ac170363776319b38cc0e9c047a06aa2e7541 (#62628)

Skipped hunks:

  • Synced repeating animations (4ed3738 / #62332) — still no local consumer.
  • Zed inspector / telemetry (example debug_selector kept only as a no-op in release).
  • reduce_motion spring snap — no local App::reduce_motion.
  • Zed scheduler::Instant / simulate_next_frame integration tests (local animations use std::time::Instant).

2. LineLayout::{split_at, paint, paint_background}

Local commit: 04d80ead7776696126a080f624c4d26884112d86

Callers can hold Arc<LineLayout> plus their own decoration runs without a large ShapedLine. Local ShapedLine never had split_at, so there is no wrapper to delegate.

Zed-Origin: 2936989f1b7a15aaf7131b0a3c17961d706fdbf5 (#60831)

3. Windows Restart Manager (WM_QUERYENDSESSION / WM_ENDSESSION)

Local commit: ccb3a7fa0041b9d27d7ca3b978562443cb2c103a

Installers can close the app cleanly. Platform::on_quit now reports whether shutdown ran synchronously; if AppCell is borrowed, Windows posts WM_QUIT instead of exiting. WM_GPUI_END_SESSION uses the unused WM_USER + 9 slot (tray is +8, network is +10).

Zed-Origin: 7f2a2c3c3ee2f23f28772dee7661fb98d3910990 (#62987)

Skipped hunks:

  • Zed crash-handler sidecar (crates/crashes) — not present here.
  • Single-instance / autostart / tray left untouched.

Protected files

Surgical edits only to app.rs (on_quit try-borrow), platform.rs (WindowOptions field + on_quit signature), and window.rs (inactive_frame_interval plumbing). No wholesale overwrite of platform window/client or wgpu_renderer.rs. Local notifications/attention APIs unchanged.

Verification

  • cargo test --locked -p adabraka-gpui-core --lib --features test-support — 234 passed
  • Focused spring / animation / LineLayout / throttle tests passed
  • cargo check --locked -p adabraka-gpui --example animation
  • cargo check --locked -p adabraka-gpui-linux --features wayland,x11
  • cargo check --locked -p adabraka-gpui-downstream-compat
  • Full adabraka-gpui --tests link failed in this environment (missing libstdc++ / libxkbcommon); not a code regression
  • Windows crate is cfg(target_os = "windows"); not compiled on this Linux host
Open in Web Open in Cursor 

Sourcery 摘要

在保留现有平台行为的同时,移植中优先级的 GPUI 动画、文本布局和 Windows 关闭功能。

新功能:

  • 添加支持中断的弹簧动画、类型化插值,以及可配置的最大重绘速率。
  • 为需要自行管理文本装饰的调用方公开 LineLayout 分割和直接绘制 API。
  • 处理 Windows Restart Manager 关闭消息,以便在系统或安装程序关闭期间干净地终止应用程序。

错误修复:

  • 当应用程序状态暂时处于借用状态时,允许退出回调报告延迟关闭。

增强功能:

  • 使非活动窗口的动画节流可配置,同时保留默认帧间隔。

文档:

  • 在变更日志中记录新的弹簧动画、动画帧速率、非活动窗口节流、LineLayout 和 Windows 关闭 API。

测试:

  • 增加对弹簧物理、插值、动画节流、LineLayout 分割和 Windows 消息槽处理的测试覆盖。
Original summary in English

Sourcery 摘要

移植中等优先级的 GPUI 动画、文本布局和 Windows 关闭功能,同时保留现有的平台行为。

新功能:

  • 添加支持中断的弹簧动画、带类型的插值以及可配置的动画重绘频率。
  • 暴露 LineLayout 拆分功能,以及直接绘制文本和背景的 API。
  • 处理 Windows Restart Manager 的关闭消息,以实现应用程序的干净终止。

错误修复:

  • 当应用程序状态已被借用时,允许退出回调安全地延迟关闭。

增强功能:

  • 使非活动窗口的动画节流可配置,同时保留现有的默认帧间隔。

文档:

  • 在变更日志中记录弹簧动画、动画帧率控制、非活动窗口节流、LineLayout API 以及 Windows 关闭处理。

测试:

  • 增加对弹簧行为和插值、动画节流、LineLayout 拆分以及 Windows 消息分配的测试覆盖。
Original summary in English

Sourcery 摘要

移植中优先级的 GPUI 动画、文本布局和 Windows 关机功能,同时保留现有的平台行为。

新功能:

  • 添加可中断的弹簧动画、类型化插值和动画帧率控制。
  • 暴露 LineLayout 拆分功能,以及直接绘制文本和背景的 API。
  • 处理 Windows Restart Manager 关机消息,实现应用程序的正常终止。

错误修复:

  • 当应用程序状态暂时被借用时,允许退出回调安全地延迟关机。

增强功能:

  • 使非活动窗口的动画节流可配置,同时保留默认帧间隔。

文档:

  • 在更新日志中记录弹簧动画、动画帧率控制、非活动窗口节流、LineLayout API 和 Windows 关机处理。

测试:

  • 增加对弹簧物理和插值、动画节流、LineLayout 拆分以及 Windows 消息路由的测试覆盖。
Original summary in English

Summary by Sourcery

Port medium-priority GPUI animation, text layout, and Windows shutdown capabilities while preserving existing platform behavior.

New Features:

  • Add interruptible spring animations, typed interpolation, and animation frame-rate controls.
  • Expose LineLayout splitting and direct text and background painting APIs.
  • Handle Windows Restart Manager shutdown messages for clean application termination.

Bug Fixes:

  • Allow quit callbacks to defer shutdown safely when application state is temporarily borrowed.

Enhancements:

  • Make inactive-window animation throttling configurable while preserving the default frame interval.

Documentation:

  • Document spring animations, animation frame-rate controls, inactive-window throttling, LineLayout APIs, and Windows shutdown handling in the changelog.

Tests:

  • Add coverage for spring physics and interpolation, animation throttling, LineLayout splitting, and Windows message routing.

@sourcery-ai

sourcery-ai Bot commented Aug 29, 2026

Copy link
Copy Markdown

审阅者指南

移植了三项相互独立的 GPUI 功能:支持解析、可重新定向且可选限制重绘速率的弹簧动画;可复用的 LineLayout 拆分与绘制 API;以及支持 Windows Restart Manager 关机处理和借用安全的延迟退出。窗口级非活动帧节流现已支持配置,同时保留现有默认值;每个功能区域都包含针对性的测试或示例覆盖。

可重新定向弹簧动画渲染的时序图

sequenceDiagram
    participant View as AnimatedElement
    participant State as SpringElementState
    participant Config as SpringConfig
    participant Window

    View->>State: with_spring(id, SpringAnimation)
    View->>State: request_layout()
    State->>Config: step(current_state, target, elapsed)
    Config-->>State: position and velocity
    State->>View: animator(element, position)
    alt spring not settled
        State->>Window: request_animation_frame()
    end
    Note over State: Target changes preserve existing velocity
Loading

受计时器限制的动画重绘时序图

sequenceDiagram
    participant Animation as AnimationElement
    participant Window
    participant Timer
    participant View

    Animation->>Animation: with_max_fps(max_fps)
    Animation->>Window: spawn(timer)
    Window->>Timer: timer(interval)
    Timer-->>Window: elapsed
    Window->>View: notify(current_view)
    View->>Animation: request_layout()
    Animation->>Window: spawn(timer)
Loading

Windows Restart Manager 关机时序图

sequenceDiagram
    participant Windows
    participant Window as WindowsWindowInner
    participant Platform as WindowsPlatformInner
    participant AppCell

    Windows->>Window: WM_QUERYENDSESSION
    Window-->>Windows: 1
    Windows->>Window: WM_ENDSESSION
    Window->>Window: SendMessageW(WM_GPUI_END_SESSION)
    Window->>Platform: handle_end_session()
    Platform->>AppCell: quit callback()
    alt AppCell available
        AppCell-->>Platform: true
        Platform->>Platform: flush logger
        Platform->>Platform: exit(0)
    else AppCell borrowed
        AppCell-->>Platform: false
        Platform->>Platform: PostQuitMessage(0)
    end
Loading

文件级变更

变更 详情 文件
添加可中断的弹簧动画原语和计时器限制的持续时间动画。
  • 实现解析阻尼弹簧步进、稳定判定、播放、重新定向和类型化插值。
  • 通过 AnimationExt::with_spring 暴露由弹簧驱动的元素,并导出新的 API。
  • 为持续时间动画添加可选的最大 FPS 调度,并使用弹簧和限 FPS 演示扩展动画示例。
  • 添加针对弹簧、插值和最大 FPS 的测试。
crates/gpui/src/spring.rs
crates/gpui/src/elements/animation.rs
crates/gpui/src/gpui.rs
crates/gpui-compat/examples/animation.rs
使窗口级别的非活动窗口动画节流支持配置。
  • 添加 WindowOptions::inactive_frame_interval,默认值保持约 30 FPS。
  • 将该选项传递到窗口帧调度中,包括使用 None 禁用节流的支持。
  • 通过测试覆盖默认、自定义、禁用、输入和热节流行为。
crates/gpui/src/platform.rs
crates/gpui/src/window.rs
暴露可复用的 LineLayout 拆分和直接绘制操作。
  • 在字节索引处分割字形运行,同时重新基准化后缀的位置和索引,并保留布局度量。
  • 使用调用方拥有的装饰运行,添加布局级前景和背景绘制。
  • 测试普通拆分、运行中间拆分以及一侧为空的拆分。
crates/gpui/src/text_system/line_layout.rs
crates/gpui/src/text_system/line.rs
处理 Windows Restart Manager 关机,同时保留安全的延迟退出行为。
  • 使用未占用的 GPUI 消息槽,为 WM_QUERYENDSESSIONWM_ENDSESSION 添加 Restart Manager 消息处理。
  • 将平台退出回调改为返回关机是否已同步完成。
  • 在应用退出回调中使用 try_borrow_mut,并在关机延迟时发布 WM_QUIT;否则在刷新日志后退出。
  • 更新平台实现,并测试消息槽分配。
crates/gpui/src/app.rs
crates/gpui/src/platform.rs
crates/gpui/src/platform/test/platform.rs
crates/gpui/src/platform/test/visual.rs
crates/gpui-linux/src/linux/platform.rs
crates/gpui-macos/src/mac/platform.rs
crates/gpui-windows/src/windows/events.rs
crates/gpui-windows/src/windows/platform.rs
记录新移植的 API 和行为。
  • 在变更日志中描述弹簧动画、动画 FPS 限制、非活动窗口节流、LineLayout API 以及 Windows 关机支持。
CHANGELOG.md

提示和命令

与 Sourcery 交互

  • 触发新的审阅: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 回复审阅评论,请 Sourcery 从该评论创建 issue。你也可以使用 @sourcery-ai issue 回复审阅评论,从中创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文的任意位置写入 @sourcery-ai summary,即可在你指定的位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审阅者指南: 在拉取请求中评论 @sourcery-ai guide,以随时生成或重新生成审阅者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,以解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,此功能会很有用。
  • 忽略所有 Sourcery 审阅: 在拉取请求中评论 @sourcery-ai dismiss,以忽略所有现有的 Sourcery 审阅。如果你想从新的审阅开始,这一功能尤其有用——别忘了评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的控制面板以:

  • 启用或禁用审阅功能,例如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Ports three independent GPUI capabilities: analytic, retargetable spring animations with optional redraw-rate limits; reusable LineLayout split and painting APIs; and Windows Restart Manager shutdown handling with borrow-safe deferred quitting. Window-level inactive-frame throttling is configurable while retaining the existing default, and each area includes focused tests or example coverage.

Sequence diagram for retargetable spring animation rendering

sequenceDiagram
    participant View as AnimatedElement
    participant State as SpringElementState
    participant Config as SpringConfig
    participant Window

    View->>State: with_spring(id, SpringAnimation)
    View->>State: request_layout()
    State->>Config: step(current_state, target, elapsed)
    Config-->>State: position and velocity
    State->>View: animator(element, position)
    alt spring not settled
        State->>Window: request_animation_frame()
    end
    Note over State: Target changes preserve existing velocity
Loading

Sequence diagram for timer-limited animation redraws

sequenceDiagram
    participant Animation as AnimationElement
    participant Window
    participant Timer
    participant View

    Animation->>Animation: with_max_fps(max_fps)
    Animation->>Window: spawn(timer)
    Window->>Timer: timer(interval)
    Timer-->>Window: elapsed
    Window->>View: notify(current_view)
    View->>Animation: request_layout()
    Animation->>Window: spawn(timer)
Loading

Sequence diagram for Windows Restart Manager shutdown

sequenceDiagram
    participant Windows
    participant Window as WindowsWindowInner
    participant Platform as WindowsPlatformInner
    participant AppCell

    Windows->>Window: WM_QUERYENDSESSION
    Window-->>Windows: 1
    Windows->>Window: WM_ENDSESSION
    Window->>Window: SendMessageW(WM_GPUI_END_SESSION)
    Window->>Platform: handle_end_session()
    Platform->>AppCell: quit callback()
    alt AppCell available
        AppCell-->>Platform: true
        Platform->>Platform: flush logger
        Platform->>Platform: exit(0)
    else AppCell borrowed
        AppCell-->>Platform: false
        Platform->>Platform: PostQuitMessage(0)
    end
Loading

File-Level Changes

Change Details Files
Add interruptible spring animation primitives and timer-capped duration animations.
  • Implement analytic damped-spring stepping, settling, playback, retargeting, and typed interpolation.
  • Expose spring-driven elements through AnimationExt::with_spring and export the new API.
  • Add optional maximum FPS scheduling for duration animations and expand the animation example with spring and capped-FPS demos.
  • Add focused spring, interpolation, and max-FPS tests.
crates/gpui/src/spring.rs
crates/gpui/src/elements/animation.rs
crates/gpui/src/gpui.rs
crates/gpui-compat/examples/animation.rs
Make inactive-window animation throttling configurable at the window level.
  • Add WindowOptions::inactive_frame_interval with the existing approximately 30 FPS default.
  • Thread the option through window frame scheduling, including support for disabling the throttle with None.
  • Cover default, custom, disabled, input, and thermal-throttling behavior with tests.
crates/gpui/src/platform.rs
crates/gpui/src/window.rs
Expose reusable LineLayout splitting and direct painting operations.
  • Split glyph runs at a byte index while rebasing suffix positions and indices and preserving layout metrics.
  • Add layout-level foreground and background painting using caller-owned decoration runs.
  • Test normal, mid-run, and empty-side splits.
crates/gpui/src/text_system/line_layout.rs
crates/gpui/src/text_system/line.rs
Handle Windows Restart Manager shutdown while preserving safe deferred quit behavior.
  • Add Restart Manager message handling for WM_QUERYENDSESSION and WM_ENDSESSION using the unused GPUI message slot.
  • Change platform quit callbacks to return whether shutdown completed synchronously.
  • Use try_borrow_mut in the app quit callback and post WM_QUIT when shutdown is deferred; otherwise exit after flushing logs.
  • Update platform implementations and test message-slot allocation.
crates/gpui/src/app.rs
crates/gpui/src/platform.rs
crates/gpui/src/platform/test/platform.rs
crates/gpui/src/platform/test/visual.rs
crates/gpui-linux/src/linux/platform.rs
crates/gpui-macos/src/mac/platform.rs
crates/gpui-windows/src/windows/events.rs
crates/gpui-windows/src/windows/platform.rs
Document the newly ported APIs and behavior.
  • Describe springs, animation FPS limits, inactive-window throttling, LineLayout APIs, and Windows shutdown support in the changelog.
CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@cursor
cursor Bot marked this pull request as ready for review August 29, 2026 10:18

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嘿——我发现了 3 个问题

面向 AI Agent 的提示
请处理此次代码审查中的评论:

## 单独评论

### 评论 1
<location path="crates/gpui/src/elements/animation.rs" line_range="324-333" />
<code_context>
+            let elapsed = now.duration_since(state.updated_at).as_secs_f32();
+            match state.playback {
+                SpringPlayback::Running => {
+                    state.spring = state.config.step(state.spring, state.target, elapsed);
+                }
+                SpringPlayback::Paused
+                | SpringPlayback::Stopped
+                | SpringPlayback::Completed
+                | SpringPlayback::Cancelled => {}
+            }
+
+            state.config = self.config;
+            state.target = self.target;
+
+            let done = match self.playback {
</code_context>
<issue_to_address>
**issue (bug_risk):** 当弹簧目标、配置或播放模式发生变化时,该元素会先使用旧目标、旧配置和旧播放模式推进之前的状态,然后才赋予新值。因此,重新设定目标的弹簧会先朝着过时状态渲染一帧,播放模式的变化也会延迟一帧生效。

**触发条件:** 已存在的弹簧元素在两次布局之间被重新设定目标,或其播放模式/配置发生变化时。

**建议修复:** 在推进状态之前,将新的目标、配置和播放模式赋给状态,同时在运行中的弹簧重新设定目标时保留现有的位置和速度。
</issue_to_address>

### 评论 2
<location path="crates/gpui-windows/src/windows/platform.rs" line_range="1030-1043" />
<code_context>
     }

+    fn handle_end_session(&self) -> Option<isize> {
+        let mut shutdown_completed = false;
+        if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
+            shutdown_completed = callback();
+        }
+        log::logger().flush();
+        if shutdown_completed {
+            std::process::exit(0);
+        }
+
+        // Shutdown couldn't run synchronously, since the AppCell is already borrowed.
+        // Windows may terminate the application as soon as we return from this handler,
+        // but posting WM_QUIT now may still let the message loop shut down first.
+        unsafe { PostQuitMessage(0) };
+        Some(0)
+    }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** 当退出回调无法借用 `AppCell` 时,`handle_end_session` 会发布 `WM_QUIT`,但不会重试该回调或运行 `App::shutdown`。这样消息循环可能在窗口、退出观察者和关闭清理仍处于活动状态时终止,因此在此更改要处理的这种确切借用状态下,Restart Manager 的关闭过程并不干净。

**触发条件:** `WM_ENDSESSION` 到达时,`AppCell` 已经被可变借用。

**建议修复:** 在允许进程退出之前,将退出回调推迟到主循环中并重试(或以其他方式调度 `App::shutdown`),而不是仅使用 `PostQuitMessage` 作为后备方案。
</issue_to_address>

### 评论 3
<location path="crates/gpui/src/text_system/line_layout.rs" line_range="138" />
<code_context>
+    /// - `suffix` contains glyphs for bytes `[byte_index, len)` with positions
+    ///   shifted left so the first glyph starts at x=0, and byte indices rebased to 0.
+    /// - `font_size`, `ascent`, and `descent` are copied to both halves.
+    pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
+        let x_offset = self.x_for_index(byte_index);
+
+        // Partition glyph runs. A single run may contribute glyphs to both halves.
+        let mut left_runs = Vec::new();
</code_context>
<issue_to_address>
**issue (bug_risk):** 传入大于 `self.len` 的字节索引会导致 `self.len - byte_index` 下溢,而放置在后缀中的任何字形也可能导致 `g.index - byte_index` 下溢。因此,该公共方法会直接 panic,而不是拒绝或安全处理超出范围的拆分。

**触发条件:** 调用方传入超出范围的字节索引时。

**建议修复:** 在计算偏移量之前,对 `byte_index > self.len` 进行断言或返回错误,使其行为符合标准拆分 API 的边界处理方式。

```suggestion
    pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
        assert!(byte_index <= self.len);
```
</issue_to_address>

Sourcery 对开源项目免费——如果您喜欢我们的审查,请考虑分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会利用反馈来改进审查结果。
Original comment in English

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="crates/gpui/src/elements/animation.rs" line_range="324-333" />
<code_context>
+            let elapsed = now.duration_since(state.updated_at).as_secs_f32();
+            match state.playback {
+                SpringPlayback::Running => {
+                    state.spring = state.config.step(state.spring, state.target, elapsed);
+                }
+                SpringPlayback::Paused
+                | SpringPlayback::Stopped
+                | SpringPlayback::Completed
+                | SpringPlayback::Cancelled => {}
+            }
+
+            state.config = self.config;
+            state.target = self.target;
+
+            let done = match self.playback {
</code_context>
<issue_to_address>
**issue (bug_risk):** When a spring target, configuration, or playback mode changes, the element advances the previous state using the previous target/configuration/playback before assigning the new values. The retargeted spring therefore renders one frame toward stale state and a playback change takes effect one frame late.

**Triggers:** When an existing spring element is retargeted or its playback/configuration is changed between layout passes.

**Suggested fix:** Assign the new target, configuration, and playback to the state before advancing it, while preserving the existing position and velocity for running retargets.
</issue_to_address>

### Comment 2
<location path="crates/gpui-windows/src/windows/platform.rs" line_range="1030-1043" />
<code_context>
     }

+    fn handle_end_session(&self) -> Option<isize> {
+        let mut shutdown_completed = false;
+        if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
+            shutdown_completed = callback();
+        }
+        log::logger().flush();
+        if shutdown_completed {
+            std::process::exit(0);
+        }
+
+        // Shutdown couldn't run synchronously, since the AppCell is already borrowed.
+        // Windows may terminate the application as soon as we return from this handler,
+        // but posting WM_QUIT now may still let the message loop shut down first.
+        unsafe { PostQuitMessage(0) };
+        Some(0)
+    }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** When the quit callback cannot borrow `AppCell`, `handle_end_session` posts `WM_QUIT` without retrying the callback or running `App::shutdown`. The message loop can then terminate with windows, quit observers, and shutdown cleanup still active, so Restart Manager shutdown is not clean in the exact borrowed-state case this change is intended to handle.

**Triggers:** When `WM_ENDSESSION` arrives while `AppCell` is already mutably borrowed.

**Suggested fix:** Defer and retry the quit callback on the main loop (or otherwise schedule `App::shutdown`) before allowing the process to exit, rather than using `PostQuitMessage` as the only fallback.
</issue_to_address>

### Comment 3
<location path="crates/gpui/src/text_system/line_layout.rs" line_range="138" />
<code_context>
+    /// - `suffix` contains glyphs for bytes `[byte_index, len)` with positions
+    ///   shifted left so the first glyph starts at x=0, and byte indices rebased to 0.
+    /// - `font_size`, `ascent`, and `descent` are copied to both halves.
+    pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
+        let x_offset = self.x_for_index(byte_index);
+
+        // Partition glyph runs. A single run may contribute glyphs to both halves.
+        let mut left_runs = Vec::new();
</code_context>
<issue_to_address>
**issue (bug_risk):** Passing a byte index greater than `self.len` makes `self.len - byte_index` underflow, and any glyph placed in the suffix can also make `g.index - byte_index` underflow. The public method consequently panics instead of rejecting or safely handling an out-of-range split.

**Triggers:** When a caller passes an out-of-range byte index.

**Suggested fix:** Assert or return an error for `byte_index > self.len` before calculating offsets, matching the bounds behavior of standard split APIs.

```suggestion
    pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
        assert!(byte_index <= self.len);
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +324 to +333
state.spring = state.config.step(state.spring, state.target, elapsed);
}
SpringPlayback::Paused
| SpringPlayback::Stopped
| SpringPlayback::Completed
| SpringPlayback::Cancelled => {}
}

state.config = self.config;
state.target = self.target;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 当弹簧目标、配置或播放模式发生变化时,该元素会先使用旧目标、旧配置和旧播放模式推进之前的状态,然后才赋予新值。因此,重新设定目标的弹簧会先朝着过时状态渲染一帧,播放模式的变化也会延迟一帧生效。

触发条件: 已存在的弹簧元素在两次布局之间被重新设定目标,或其播放模式/配置发生变化时。

建议修复: 在推进状态之前,将新的目标、配置和播放模式赋给状态,同时在运行中的弹簧重新设定目标时保留现有的位置和速度。

Original comment in English

issue (bug_risk): When a spring target, configuration, or playback mode changes, the element advances the previous state using the previous target/configuration/playback before assigning the new values. The retargeted spring therefore renders one frame toward stale state and a playback change takes effect one frame late.

Triggers: When an existing spring element is retargeted or its playback/configuration is changed between layout passes.

Suggested fix: Assign the new target, configuration, and playback to the state before advancing it, while preserving the existing position and velocity for running retargets.

Comment on lines +1030 to +1043
let mut shutdown_completed = false;
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
shutdown_completed = callback();
}
log::logger().flush();
if shutdown_completed {
std::process::exit(0);
}

// Shutdown couldn't run synchronously, since the AppCell is already borrowed.
// Windows may terminate the application as soon as we return from this handler,
// but posting WM_QUIT now may still let the message loop shut down first.
unsafe { PostQuitMessage(0) };
Some(0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 当退出回调无法借用 AppCell 时,handle_end_session 会发布 WM_QUIT,但不会重试该回调或运行 App::shutdown。这样消息循环可能在窗口、退出观察者和关闭清理仍处于活动状态时终止,因此在此更改要处理的这种确切借用状态下,Restart Manager 的关闭过程并不干净。

触发条件: WM_ENDSESSION 到达时,AppCell 已经被可变借用。

建议修复: 在允许进程退出之前,将退出回调推迟到主循环中并重试(或以其他方式调度 App::shutdown),而不是仅使用 PostQuitMessage 作为后备方案。

Original comment in English

issue (bug_risk): When the quit callback cannot borrow AppCell, handle_end_session posts WM_QUIT without retrying the callback or running App::shutdown. The message loop can then terminate with windows, quit observers, and shutdown cleanup still active, so Restart Manager shutdown is not clean in the exact borrowed-state case this change is intended to handle.

Triggers: When WM_ENDSESSION arrives while AppCell is already mutably borrowed.

Suggested fix: Defer and retry the quit callback on the main loop (or otherwise schedule App::shutdown) before allowing the process to exit, rather than using PostQuitMessage as the only fallback.

/// - `suffix` contains glyphs for bytes `[byte_index, len)` with positions
/// shifted left so the first glyph starts at x=0, and byte indices rebased to 0.
/// - `font_size`, `ascent`, and `descent` are copied to both halves.
pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 传入大于 self.len 的字节索引会导致 self.len - byte_index 下溢,而放置在后缀中的任何字形也可能导致 g.index - byte_index 下溢。因此,该公共方法会直接 panic,而不是拒绝或安全处理超出范围的拆分。

触发条件: 调用方传入超出范围的字节索引时。

建议修复: 在计算偏移量之前,对 byte_index > self.len 进行断言或返回错误,使其行为符合标准拆分 API 的边界处理方式。

Suggested change
pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
assert!(byte_index <= self.len);
Original comment in English

issue (bug_risk): Passing a byte index greater than self.len makes self.len - byte_index underflow, and any glyph placed in the suffix can also make g.index - byte_index underflow. The public method consequently panics instead of rejecting or safely handling an out-of-range split.

Triggers: When a caller passes an out-of-range byte index.

Suggested fix: Assert or return an error for byte_index > self.len before calculating offsets, matching the bounds behavior of standard split APIs.

Suggested change
pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
assert!(byte_index <= self.len);

…-window throttle

Port spring simulations (SpringConfig/SpringAnimation/with_spring),
Animation::with_max_fps timer-driven redraws, and
WindowOptions::inactive_frame_interval so overlay/HUD/daemon windows can
keep a chosen inactive frame rate. Adapt the animation example. Skip
synced repeating animations (no local consumer) and Zed inspector/telemetry.

Zed-Origin: 8b1497dbd22fb06f5838a7c0b84a1e54fafa71bc
Zed-Origin: dd04a229dd22700ff43815b8514453e197c333b7
Zed-Origin: 511ac170363776319b38cc0e9c047a06aa2e7541

Co-authored-by: freefcw <freefcw@gmail.com>
Move glyph partitioning onto LineLayout::split_at and expose
paint/paint_background that take explicit decoration runs so callers can
hold Arc<LineLayout> without a large ShapedLine.

Zed-Origin: 2936989f1b7a15aaf7131b0a3c17961d706fdbf5

Co-authored-by: freefcw <freefcw@gmail.com>
Honor WM_QUERYENDSESSION and WM_ENDSESSION so installers can close the
app cleanly. Platform::on_quit now reports whether shutdown ran
synchronously; if the AppCell is borrowed, Windows posts WM_QUIT instead
of exiting. Skip Zed crash-handler sidecar changes. Leave single-instance,
autostart, and tray behavior unchanged.

Zed-Origin: 7f2a2c3c3ee2f23f28772dee7661fb98d3910990

Co-authored-by: freefcw <freefcw@gmail.com>
@cursor
cursor Bot force-pushed the cursor/zed-gpui-medium-ports-81de branch from 09e7cde to ccb3a7f Compare August 29, 2026 12:06
@freefcw
freefcw merged commit 237df34 into develop/0.9 Aug 29, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant