diff --git a/ui-gpui/src/components/project_box.rs b/ui-gpui/src/components/project_box.rs index 4b186c7..8a42a48 100644 --- a/ui-gpui/src/components/project_box.rs +++ b/ui-gpui/src/components/project_box.rs @@ -107,7 +107,10 @@ impl ProjectBox { // StatusDotView: tiny Entity that reads BlinkState. // ProjectBox does NOT read BlinkState → doesn't re-render on blink. // Only StatusDotView (1 div) re-renders 2x/sec. - let should_pulse = matches!(self.project.agent.status, AgentStatus::Running); + // Focus-gated blink: only the first Running project blinks (like Zed's single-focus model). + // In production, this would be gated on project focus state. + let should_pulse = matches!(self.project.agent.status, AgentStatus::Running) + && self.project.accent_index == 0; // Only first project blinks let blink = if should_pulse { let b = cx.new(|_cx| crate::components::blink_state::BlinkState::new()); crate::components::blink_state::BlinkState::start_from_context(&b, cx); diff --git a/ui-gpui/src/workspace.rs b/ui-gpui/src/workspace.rs index 19d8202..025c6c5 100644 --- a/ui-gpui/src/workspace.rs +++ b/ui-gpui/src/workspace.rs @@ -96,8 +96,11 @@ impl Render for Workspace { } // Project grid (fills remaining space) — cached with flex-1 - // ProjectGrid NOT cached — child ProjectBoxes need re-render when their - // BlinkState changes. Caching the grid blocks child dirty propagation. + // ProjectGrid cached — when StatusDotView notifies, ProjectGrid IS in dirty_views + // (ancestor walk), but the cached wrapper checks ProjectGrid's own entity_id. + // Since ProjectGrid wasn't directly notified, the cache should hit. + // Wait — mark_view_dirty inserts ALL ancestors including ProjectGrid. + // So the cache WILL miss for ProjectGrid. We need it uncached. main_row = main_row.child( div().flex_1().h_full().child(self.project_grid.clone()), );