fix(input): unresponsive clients get uncaptured

This commit is contained in:
Nova
2025-04-07 09:16:59 -07:00
committed by Nova
parent fe9ae8225c
commit 173b033963
3 changed files with 28 additions and 4 deletions

View File

@@ -23,12 +23,14 @@ use std::{
iter::FromIterator,
path::PathBuf,
sync::{Arc, OnceLock},
time::Instant,
};
use tokio::{net::UnixStream, task::JoinHandle};
use tokio::{net::UnixStream, sync::watch, task::JoinHandle};
use tracing::info;
lazy_static! {
pub static ref CLIENTS: OwnedRegistry<Client> = OwnedRegistry::new();
static ref INTERNAL_CLIENT_MESSAGE_TIMES: (watch::Sender<Instant>, watch::Receiver<Instant>) = watch::channel(Instant::now());
pub static ref INTERNAL_CLIENT: Arc<Client> = CLIENTS.add(Client {
pid: None,
// env: None,
@@ -38,14 +40,18 @@ lazy_static! {
flush_join_handle: OnceLock::new(),
disconnect_status: OnceLock::new(),
message_sender_handle: None,
id_counter: CounterU32::new(0),
message_last_received: INTERNAL_CLIENT_MESSAGE_TIMES.1.clone(),
message_sender_handle: None,
scenegraph: Default::default(),
root: OnceLock::new(),
base_resource_prefixes: Default::default(),
state: OnceLock::default(),
});
}
pub fn tick_internal_client() {
let _ = INTERNAL_CLIENT_MESSAGE_TIMES.0.send(Instant::now());
}
pub fn get_env(pid: i32) -> Result<FxHashMap<String, String>, std::io::Error> {
let env = fs::read_to_string(format!("/proc/{pid}/environ"))?;
@@ -69,6 +75,7 @@ pub struct Client {
disconnect_status: OnceLock<Result<()>>,
id_counter: CounterU32,
message_last_received: watch::Receiver<Instant>,
pub message_sender_handle: Option<MessageSenderHandle>,
pub scenegraph: Arc<Scenegraph>,
pub root: OnceLock<Arc<Root>>,
@@ -95,6 +102,7 @@ impl Client {
.and_then(state)
.unwrap_or_else(|| Arc::new(ClientStateParsed::default()));
let (message_time_tx, message_last_received) = watch::channel(Instant::now());
let client = CLIENTS.add(Client {
pid,
// env,
@@ -105,6 +113,7 @@ impl Client {
disconnect_status: OnceLock::new(),
id_counter: CounterU32::new(256),
message_last_received,
message_sender_handle: Some(messenger_tx.handle()),
scenegraph: scenegraph.clone(),
root: OnceLock::new(),
@@ -148,6 +157,7 @@ impl Client {
if let Err(e) = messenger_rx.dispatch(&*scenegraph).await {
client.disconnect(Err(e.into()));
}
let _ = message_time_tx.send(Instant::now());
}
}
},
@@ -206,6 +216,11 @@ impl Client {
.ok_or_else(|| eyre!("{} not found", name))
}
pub fn unresponsive(&self) -> bool {
let time_since_last_message = self.message_last_received.borrow().elapsed();
time_since_last_message.as_millis() > 500
}
pub fn disconnect(&self, reason: Result<()>) {
let _ = self.disconnect_status.set(reason);
if let Some(dispatch_join_handle) = self.dispatch_join_handle.get() {

View File

@@ -11,7 +11,7 @@ use crate::nodes::items::camera;
use crate::nodes::{audio, drawable, input};
use clap::Parser;
use core::client::Client;
use core::client::{Client, tick_internal_client};
use core::task;
use directories::ProjectDirs;
use objects::ServerObjects;
@@ -307,6 +307,7 @@ fn stereokit_loop(
Duration::from_micros(250),
);
tick_internal_client();
#[cfg(feature = "wayland")]
wayland.update();
drawable::draw(token);

View File

@@ -159,7 +159,15 @@ impl InputMethod {
.iter()
.filter_map(Weak::upgrade)
.collect::<Registry<InputHandler>>();
self.captures.retain(|handler| sent.contains(handler));
self.captures.retain(|handler| {
!handler
.spatial
.node()
.and_then(|n| n.get_client())
.map(|c| c.unresponsive())
.unwrap_or(false)
&& sent.contains(handler)
});
}
}
impl InputMethodAspect for InputMethod {