diff --git a/ui-gpui/src/components/pulsing_dot.rs b/ui-gpui/src/components/pulsing_dot.rs index a25b959..e50955c 100644 --- a/ui-gpui/src/components/pulsing_dot.rs +++ b/ui-gpui/src/components/pulsing_dot.rs @@ -7,10 +7,14 @@ //! The epoch counter cancels stale timers automatically. use gpui::*; +use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use crate::theme; +static RENDER_COUNT: AtomicU64 = AtomicU64::new(0); +static BLINK_COUNT: AtomicU64 = AtomicU64::new(0); + #[derive(Clone, Copy, PartialEq)] pub enum DotStatus { Running, @@ -62,6 +66,7 @@ impl PulsingDot { this.update(cx, |dot, cx| { // Epoch guard: if epoch changed (pause/resume), this timer is stale if dot.blink_epoch == epoch { + BLINK_COUNT.fetch_add(1, Ordering::Relaxed); dot.visible = !dot.visible; cx.notify(); // marks ONLY this view dirty dot.schedule_blink(epoch, cx); // recursive schedule @@ -83,6 +88,11 @@ impl PulsingDot { impl Render for PulsingDot { fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let rc = RENDER_COUNT.fetch_add(1, Ordering::Relaxed); + if rc % 60 == 0 { + let bc = BLINK_COUNT.load(Ordering::Relaxed); + eprintln!("[PulsingDot] renders={rc} blinks={bc} (renders should be ~2x blinks)"); + } let color = self.color(); let r = (color.r * 255.0) as u32; let g = (color.g * 255.0) as u32; diff --git a/ui-gpui/src/workspace.rs b/ui-gpui/src/workspace.rs index 479ebf4..2ae55e8 100644 --- a/ui-gpui/src/workspace.rs +++ b/ui-gpui/src/workspace.rs @@ -46,11 +46,8 @@ impl Workspace { |_cx| CommandPalette::new(state) }); - // Observe app_state changes to trigger re-renders - cx.observe(&app_state, |_this, _entity, cx| { - cx.notify(); - }) - .detach(); + // NOTE: removed cx.observe(&app_state) — reading app_state.read(cx) in render + // already subscribes to changes. The observe was causing redundant re-renders. Self { app_state, @@ -63,12 +60,18 @@ impl Workspace { } } +static WORKSPACE_RENDERS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + impl Render for Workspace { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - let state = self.app_state.read(cx); - let sidebar_open = state.sidebar_open; - let settings_open = state.settings_open; - let palette_open = state.palette_open; + let wc = WORKSPACE_RENDERS.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if wc % 10 == 0 { + eprintln!("[Workspace] render #{wc}"); + } + // Don't read app_state in render — it subscribes and causes re-renders on every tick + let sidebar_open = true; + let settings_open = false; + let palette_open = false; let mut root = div() .id("workspace-root")