From d5680d84fd1df3b592424eae5c50d54642f0727d Mon Sep 17 00:00:00 2001 From: JJ Liebig Date: Mon, 28 Sep 2026 17:16:27 +0200 Subject: fix: capture Windows host default colors at startup (#4710) refs #1530 refs #4369 --- src/client/shell_runtime.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'src/client/shell_runtime.rs') diff --git a/src/client/shell_runtime.rs b/src/client/shell_runtime.rs index d0eafdf6..5e1da58c 100644 --- a/src/client/shell_runtime.rs +++ b/src/client/shell_runtime.rs @@ -751,6 +751,10 @@ pub(super) fn finish_client_shell_input( } continue; } + if endpoints.active_surface_available() { + write_to_server(endpoints, &request).map_err(ClientError::ConnectionLost)?; + } + continue; } // Host focus belongs to a pending target even when the source has gone offline or has // already had its surface revoked. Route it before the ordinary source-online gate. @@ -791,3 +795,109 @@ pub(super) fn finish_client_shell_input( } Ok(false) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn host_color_reaches_server_before_first_snapshot() { + #[derive(Clone)] + struct Capture(std::sync::Arc>>); + + impl endpoint::EndpointTransport for Capture { + fn send(&mut self, message: &ClientMessage) -> std::io::Result<()> { + self.0.lock().unwrap().push(message.clone()); + Ok(()) + } + } + + let sent = std::sync::Arc::new(std::sync::Mutex::new(Vec::new())); + let mut endpoints = endpoint::EndpointRegistry::new( + Capture(sent.clone()), + 1, + endpoint::EndpointNegotiation::new(Vec::new(), Vec::new()), + ); + let mut state = ClientState::test_new(); + assert!(!state + .shell + .as_ref() + .unwrap() + .endpoint_is_online(&endpoint::ClientEndpointId::Local)); + let outcome = state.shell.as_mut().unwrap().handle_raw_events(vec![ + crate::raw_input::RawInputEvent::HostDefaultColor { + kind: crate::terminal_theme::DefaultColorKind::Background, + color: crate::terminal_theme::RgbColor { + r: 0x11, + g: 0x22, + b: 0x33, + }, + }, + ]); + let mut pending_activation = None; + let mut endpoint_commands = endpoint_commands::EndpointCommands::default(); + let mut prefix_input_source = crate::platform::RealPrefixInputSource::default(); + let mut scheduled_activation = None; + finish_client_shell_input( + &mut state, + outcome, + None, + &mut endpoints, + &mut pending_activation, + &mut endpoint_commands, + &mut prefix_input_source, + &mut scheduled_activation, + ) + .unwrap(); + + assert_eq!( + *sent.lock().unwrap(), + vec![ClientMessage::ClientShellHostTheme { + update: crate::protocol::ClientHostThemeUpdate::DefaultColor { + kind: crate::protocol::ClientHostDefaultColorKind::Background, + color: crate::protocol::ClientHostColor { + r: 0x11, + g: 0x22, + b: 0x33, + }, + }, + }] + ); + + let local = endpoint::ClientEndpointId::Local; + assert!(endpoints.set_surface_active(&local, false)); + let outcome = state.shell.as_mut().unwrap().handle_raw_events(vec![ + crate::raw_input::RawInputEvent::HostDefaultColor { + kind: crate::terminal_theme::DefaultColorKind::Foreground, + color: crate::terminal_theme::RgbColor { r: 4, g: 5, b: 6 }, + }, + ]); + finish_client_shell_input( + &mut state, + outcome, + None, + &mut endpoints, + &mut pending_activation, + &mut endpoint_commands, + &mut prefix_input_source, + &mut scheduled_activation, + ) + .unwrap(); + assert_eq!(sent.lock().unwrap().len(), 1); + + assert!(endpoints.set_surface_active(&local, true)); + state.replay_host_theme(&mut endpoints, &local); + let messages = sent.lock().unwrap(); + assert_eq!(messages.len(), 3); + assert_eq!(messages[1], messages[0]); + assert_eq!( + messages[2], + ClientMessage::ClientShellHostTheme { + update: crate::protocol::ClientHostThemeUpdate::DefaultColor { + kind: crate::protocol::ClientHostDefaultColorKind::Foreground, + color: crate::protocol::ClientHostColor { r: 4, g: 5, b: 6 }, + }, + } + ); + } +} -- cgit v1.2.3