use { crate::{ client::{Client, ClientError, ClientId}, leaks::Tracker, object::{Object, Version}, utils::copyhashmap::CopyHashMap, wire::{ JayClientQueryId, jay_client_query::{ AddAll, AddId, Comm, Destroy, Done, End, Exe, Execute, IsXwayland, JayClientQueryRequestHandler, Pid, SandboxAppId, SandboxEngine, SandboxInstanceId, Sandboxed, Start, Tag, Uid, }, }, }, std::{cell::Cell, rc::Rc}, thiserror::Error, }; pub struct JayClientQuery { pub id: JayClientQueryId, pub client: Rc, pub tracker: Tracker, pub version: Version, ids: CopyHashMap, all: Cell, } const TAG_SINCE: Version = Version(25); impl JayClientQuery { pub fn new(client: &Rc, id: JayClientQueryId, version: Version) -> Self { Self { id, client: client.clone(), tracker: Default::default(), version, ids: Default::default(), all: Cell::new(false), } } } impl JayClientQueryRequestHandler for JayClientQuery { type Error = JayClientQueryError; fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { self.client.remove_obj(self)?; Ok(()) } fn execute(&self, _req: Execute, _slf: &Rc) -> Result<(), Self::Error> { let handle_client = |client: &Rc| { self.client.event(Start { self_id: self.id, id: client.id.raw(), }); if !client.is_xwayland { self.client.event(Uid { self_id: self.id, uid: client.pid_info.uid, }); self.client.event(Pid { self_id: self.id, pid: client.pid_info.pid, }); self.client.event(Comm { self_id: self.id, comm: &client.pid_info.comm, }); self.client.event(Exe { self_id: self.id, exe: &client.pid_info.exe, }); } if client.acceptor.sandboxed { self.client.event(Sandboxed { self_id: self.id }); } if client.is_xwayland { self.client.event(IsXwayland { self_id: self.id }); } if let Some(engine) = &client.acceptor.sandbox_engine { self.client.event(SandboxEngine { self_id: self.id, engine, }); } if let Some(app_id) = &client.acceptor.app_id { self.client.event(SandboxAppId { self_id: self.id, app_id, }); } if let Some(instance_id) = &client.acceptor.instance_id { self.client.event(SandboxInstanceId { self_id: self.id, instance_id, }); } if self.version >= TAG_SINCE && let Some(tag) = &client.acceptor.tag { self.client.event(Tag { self_id: self.id, tag, }); } self.client.event(End { self_id: self.id }); }; if self.all.get() { for client in self.client.state.clients.clients.borrow().values() { handle_client(&client.data); } } else { for &id in self.ids.lock().keys() { let Ok(client) = self.client.state.clients.get(id) else { continue; }; handle_client(&client); } } self.client.event(Done { self_id: self.id }); Ok(()) } fn add_all(&self, _req: AddAll, _slf: &Rc) -> Result<(), Self::Error> { self.all.set(true); Ok(()) } fn add_id(&self, req: AddId, _slf: &Rc) -> Result<(), Self::Error> { self.ids.set(ClientId::from_raw(req.id), ()); Ok(()) } } object_base! { self = JayClientQuery; version = self.version; } impl Object for JayClientQuery {} simple_add_obj!(JayClientQuery); #[derive(Debug, Error)] pub enum JayClientQueryError { #[error(transparent)] ClientError(Box), } efrom!(JayClientQueryError, ClientError);