diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 18:10:48 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 18:11:22 +0300 |
| commit | c269eeea138c002b46844b4d25c8af0c34e72447 (patch) | |
| tree | 30e482d3205cd408dfdbe533ac1377b1a8c103e9 /src/client | |
| parent | fff55440305437b2e221156d9e6a5f59e7853213 (diff) | |
fix: allow larger kitty graphics frames
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/mod.rs | 58 |
1 files changed, 26 insertions, 32 deletions
diff --git a/src/client/mod.rs b/src/client/mod.rs index 075eeb55..00e1b138 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -33,7 +33,7 @@ use tracing::{debug, info, warn}; use crate::server::headless::client_socket_path; use crate::server::protocol::{ self, ClientMessage, NotifyKind, RenderEncoding, ServerMessage, MAX_FRAME_SIZE, - PROTOCOL_VERSION, + MAX_GRAPHICS_FRAME_SIZE, PROTOCOL_VERSION, }; static RECEIVED_KITTY_GRAPHICS_IDS: OnceLock<Mutex<HashSet<u32>>> = OnceLock::new(); @@ -468,7 +468,17 @@ async fn run_client_loop( let server_read_tx = event_tx.clone(); let read_stream = stream.try_clone().map_err(ClientError::ConnectionFailed)?; std::thread::spawn(move || { - server_reader_thread(read_stream, server_read_tx, &server_read_quit); + let max_frame_size = if kitty_graphics_enabled { + MAX_GRAPHICS_FRAME_SIZE + } else { + MAX_FRAME_SIZE + }; + server_reader_thread( + read_stream, + server_read_tx, + &server_read_quit, + max_frame_size, + ); }); // Use the original stream for writing (blocking is fine since we write @@ -588,6 +598,7 @@ fn server_reader_thread( mut stream: UnixStream, event_tx: tokio::sync::mpsc::Sender<ClientLoopEvent>, should_quit: &Arc<AtomicBool>, + max_frame_size: usize, ) { // Ensure the read stream is in blocking mode to avoid WouldBlock errors // from read_exact inside read_message. The stream should already be @@ -603,7 +614,7 @@ fn server_reader_thread( break; } - match protocol::read_message(&mut stream, MAX_FRAME_SIZE) { + match protocol::read_message(&mut stream, max_frame_size) { Ok(msg) => { if event_tx .blocking_send(ClientLoopEvent::ServerMessage(msg)) @@ -730,30 +741,20 @@ fn forward_clipboard(data: &str) { // Frame output // --------------------------------------------------------------------------- -const SYNC_OUTPUT_END: &[u8] = b"\x1b[?2026l"; - fn write_encoded_frame_with_graphics( mut writer: impl io::Write, encoded: &[u8], graphics: &[u8], ) -> io::Result<()> { + writer.write_all(encoded)?; if graphics.is_empty() { - return writer.write_all(encoded); - } - - record_received_kitty_graphics(graphics); - - if let Some(sync_end) = rfind_subslice(encoded, SYNC_OUTPUT_END) { - writer.write_all(&encoded[..sync_end])?; - writer.write_all(graphics)?; - writer.write_all(&encoded[sync_end..])?; return Ok(()); } - writer.write_all(b"\x1b[?2026h")?; - writer.write_all(encoded)?; + record_received_kitty_graphics(graphics); + writer.write_all(b"\x1b7")?; writer.write_all(graphics)?; - writer.write_all(SYNC_OUTPUT_END) + writer.write_all(b"\x1b8") } fn contains_kitty_graphics_bytes(bytes: &[u8]) -> bool { @@ -827,16 +828,6 @@ fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> { .position(|window| window == needle) } -fn rfind_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> { - if needle.is_empty() || needle.len() > haystack.len() { - return None; - } - - haystack - .windows(needle.len()) - .rposition(|window| window == needle) -} - // --------------------------------------------------------------------------- // Resize polling // --------------------------------------------------------------------------- @@ -920,7 +911,7 @@ mod tests { use super::*; #[test] - fn graphics_bytes_are_inserted_before_blit_sync_end() { + fn graphics_bytes_are_written_after_blit_with_saved_cursor() { let mut output = Vec::new(); write_encoded_frame_with_graphics( &mut output, @@ -929,15 +920,18 @@ mod tests { ) .unwrap(); - assert_eq!(output, b"\x1b[?2026htextgraphics\x1b[?2026lcursor"); + assert_eq!( + output, + b"\x1b[?2026htext\x1b[?2026lcursor\x1b7graphics\x1b8" + ); } #[test] - fn graphics_bytes_fallback_wraps_unsynchronized_blit() { + fn empty_graphics_writes_only_blit_frame() { let mut output = Vec::new(); - write_encoded_frame_with_graphics(&mut output, b"text", b"graphics").unwrap(); + write_encoded_frame_with_graphics(&mut output, b"text", b"").unwrap(); - assert_eq!(output, b"\x1b[?2026htextgraphics\x1b[?2026l"); + assert_eq!(output, b"text"); } #[test] |
