aboutsummaryrefslogtreecommitdiff
path: root/src/client/shell_runtime.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/shell_runtime.rs')
-rw-r--r--src/client/shell_runtime.rs110
1 files changed, 110 insertions, 0 deletions
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<std::sync::Mutex<Vec<ClientMessage>>>);
+
+ 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 },
+ },
+ }
+ );
+ }
+}