diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 02:50:00 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 02:50:00 +0300 |
| commit | ed4253d6031c9a3b12ddd6dfc7d7bf39480ae761 (patch) | |
| tree | 315cea3ee7b5ad3a7c3f9fb31272064a0eed5dd2 /src/server | |
| parent | 287bf51640f8e1bed227cb27d93377d962851196 (diff) | |
feat: add tmux-style mouse capture config
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/headless.rs | 42 | ||||
| -rw-r--r-- | src/server/protocol.rs | 15 |
2 files changed, 57 insertions, 0 deletions
diff --git a/src/server/headless.rs b/src/server/headless.rs index f490ec45..3ff3e587 100644 --- a/src/server/headless.rs +++ b/src/server/headless.rs @@ -205,6 +205,8 @@ struct ClientConnection { graphics_cache: crate::kitty_graphics::HostGraphicsCache, /// Whether a render was skipped because the render channel was full. render_pending: bool, + /// Last host mouse capture mode sent to this client. + host_mouse_capture_active: Option<bool>, /// Channels for sending framed ServerMessage data to the client writer thread. writer: Option<ClientWriter>, } @@ -228,6 +230,7 @@ impl ClientConnection { render_state: ClientRenderState::new(render_encoding), graphics_cache: crate::kitty_graphics::HostGraphicsCache::default(), render_pending: false, + host_mouse_capture_active: None, writer, } } @@ -416,6 +419,7 @@ impl HeadlessServer { } self.drain_client_sound_config_reload_request(); + self.stream_host_mouse_capture_mode(); self.app.sync_headless_animation_timer(now); @@ -1423,6 +1427,44 @@ impl HeadlessServer { changed } + fn stream_host_mouse_capture_mode(&mut self) { + let enabled = self.app.state.should_capture_host_mouse(); + let serialized = match Self::frame_server_message(&ServerMessage::MouseCapture { enabled }) + { + Ok(framed) => framed, + Err(err) => { + warn!(err = %err, "failed to serialize mouse capture mode for clients"); + return; + } + }; + + let mut broken_clients: Vec<u64> = Vec::new(); + for (&client_id, client) in &mut self.clients { + if client.host_mouse_capture_active == Some(enabled) { + continue; + } + let Some(writer) = &client.writer else { + continue; + }; + if writer.control.send(serialized.clone()).is_err() { + debug!( + client_id, + "client writer channel closed during mouse capture update" + ); + broken_clients.push(client_id); + continue; + } + client.host_mouse_capture_active = Some(enabled); + } + + for client_id in broken_clients { + let foreground_changed = self.remove_client(client_id); + if foreground_changed { + self.resize_shared_runtime_to_effective_size(); + } + } + } + /// Renders the current state to client-sized virtual buffers and streams /// frames to all connected clients. fn render_and_stream(&mut self) { diff --git a/src/server/protocol.rs b/src/server/protocol.rs index 8748c41c..e0a3c4a0 100644 --- a/src/server/protocol.rs +++ b/src/server/protocol.rs @@ -294,6 +294,12 @@ pub enum ServerMessage { /// Client-local sound config changed on disk; refresh it without reconnecting. ReloadSoundConfig, + + /// Whether the client should currently capture host mouse input. + MouseCapture { + /// True when Herdr mouse UI is enabled or the focused pane app requests mouse reporting. + enabled: bool, + }, } // --------------------------------------------------------------------------- @@ -799,6 +805,15 @@ mod tests { assert_eq!(msg, decoded); } + #[test] + fn server_mouse_capture_roundtrip() { + let msg = ServerMessage::MouseCapture { enabled: true }; + let encoded = bincode::serde::encode_to_vec(&msg, bincode::config::standard()).unwrap(); + let (decoded, _): (ServerMessage, _) = + bincode::serde::decode_from_slice(&encoded, bincode::config::standard()).unwrap(); + assert_eq!(msg, decoded); + } + // ---- Framing ---- #[test] |
