diff --git a/libs/cua-driver/rust/crates/cursor-overlay/src/render_state.rs b/libs/cua-driver/rust/crates/cursor-overlay/src/render_state.rs index 34a07183a2..ef208c3ffa 100644 --- a/libs/cua-driver/rust/crates/cursor-overlay/src/render_state.rs +++ b/libs/cua-driver/rust/crates/cursor-overlay/src/render_state.rs @@ -96,6 +96,7 @@ impl RenderStateCore { let palette = cfg.palette(); let motion = cfg.motion.clone(); let shape = cfg.shape.clone(); + let visible = cfg.enabled; Self { cfg, palette, @@ -111,7 +112,7 @@ impl RenderStateCore { spring_tgt: None, click_t: None, pressed: false, - visible: true, + visible, // was hardcoded true — respect config.enabled (#1777) idle_secs: 0.0, idle_alpha: 1.0, pinned_wid: None, @@ -466,6 +467,7 @@ impl RenderStateCore { } OverlayCommand::SetEnabled(v) => { self.visible = v; + self.cfg.enabled = v; // keep cfg.enabled in sync with visible (#1900) true } OverlayCommand::SetMotion(m) => { diff --git a/libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs b/libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs index edd4d65d45..a341c572d7 100644 --- a/libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs +++ b/libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs @@ -156,7 +156,10 @@ pub fn init(cfg: CursorConfig) { *CMD_RX_CELL.lock().unwrap() = Some(rx); *ARRIVAL_TX.lock().unwrap() = Some(HashMap::new()); let mut cursors = IndexMap::new(); - cursors.insert("default".to_owned(), RenderState::new(cfg.clone())); + // Default cursor starts disabled — see state.rs:new() and #1777. + let mut default_cfg = cfg.clone(); + default_cfg.enabled = false; + cursors.insert("default".to_owned(), RenderState::new(default_cfg)); *RENDER.lock().unwrap() = Some(RenderMap { cursors, win_w: 0.0, diff --git a/libs/cua-driver/rust/crates/platform-macos/src/cursor/state.rs b/libs/cua-driver/rust/crates/platform-macos/src/cursor/state.rs index 931673484f..eff1b3eb4d 100644 --- a/libs/cua-driver/rust/crates/platform-macos/src/cursor/state.rs +++ b/libs/cua-driver/rust/crates/platform-macos/src/cursor/state.rs @@ -59,8 +59,17 @@ pub struct CursorRegistry { impl CursorRegistry { pub fn new() -> Self { let mut map = HashMap::new(); + let default_cfg = CursorConfig { + // Default cursor starts DISABLED. The anonymous / non-session + // path must never render a cursor — the documented contract is + // "without a session, actions run cursor-less." A session's + // first enable/start_session call activates its own cursor. + // See #1777. + enabled: false, + ..CursorConfig::default() + }; let default = CursorState { - config: CursorConfig::default(), + config: default_cfg, position: None, }; map.insert("default".into(), default); @@ -203,15 +212,17 @@ mod tests { } #[test] - fn default_cursor_unaffected_by_guard() { - // "default" is seeded and is never tombstoned — its mutators still work. + fn default_cursor_starts_disabled() { + // Default cursor is seeded disabled — anonymous calls must be + // cursor-less per the documented contract. See #1777. let reg = CursorRegistry::new(); assert!(!cua_driver_core::session::is_session_ended("default")); - reg.set_enabled("default", false); - reg.update_position("default", 1.0, 2.0); let s = reg.get("default").expect("default cursor always present"); - assert!(!s.config.enabled); - assert_eq!(s.position.as_ref().map(|p| (p.x, p.y)), Some((1.0, 2.0))); + assert!(!s.config.enabled, "default cursor must start disabled"); + // But mutators still work — a session that enables it should succeed. + reg.set_enabled("default", true); + let s2 = reg.get("default").unwrap(); + assert!(s2.config.enabled); } #[test] diff --git a/libs/cua-driver/rust/crates/platform-macos/src/tools/cursor_tools.rs b/libs/cua-driver/rust/crates/platform-macos/src/tools/cursor_tools.rs index c927f0144a..e16c60a2af 100644 --- a/libs/cua-driver/rust/crates/platform-macos/src/tools/cursor_tools.rs +++ b/libs/cua-driver/rust/crates/platform-macos/src/tools/cursor_tools.rs @@ -603,8 +603,9 @@ mod tests { }; assert!(read_for(&json!({ "session": "sessA" }))); assert!(!read_for(&json!({ "session": "sessB" }))); - // Anonymous caller (no session) falls back to the seeded default (on). - assert!(read_for(&json!({}))); + // Anonymous caller (no session) falls back to the seeded default, + // which starts disabled per #1777. + assert!(!read_for(&json!({}))); } #[test]