1
0
Fork 0
forked from wry/wry
wry/src/ei/ei_ifs/ei_connection.rs
2025-02-21 10:44:29 +01:00

161 lines
4.9 KiB
Rust

use {
crate::{
ei::{
EiContext,
ei_client::{EiClient, EiClientError},
ei_ifs::{
ei_callback::EiCallback,
ei_seat::{
EI_CAP_BUTTON, EI_CAP_KEYBOARD, EI_CAP_POINTER, EI_CAP_POINTER_ABSOLUTE,
EI_CAP_SCROLL, EI_CAP_TOUCHSCREEN, EiSeat,
},
},
ei_object::{EiObject, EiObjectId, EiVersion},
},
ifs::wl_seat::WlSeatGlobal,
leaks::Tracker,
wire_ei::{
EiButton, EiConnectionId, EiKeyboard, EiPointer, EiPointerAbsolute, EiScroll,
EiTouchscreen,
ei_connection::{
Disconnect, Disconnected, EiConnectionRequestHandler, InvalidObject, Seat,
},
},
},
std::{cell::Cell, rc::Rc},
thiserror::Error,
};
pub struct EiConnection {
pub id: EiConnectionId,
pub client: Rc<EiClient>,
pub tracker: Tracker<Self>,
pub version: EiVersion,
}
impl EiConnection {
pub fn send_invalid_object(&self, id: EiObjectId) {
self.client.event(InvalidObject {
self_id: self.id,
last_serial: self.client.last_serial(),
invalid_id: id,
});
}
pub fn send_disconnected(&self, error: Option<&str>) {
self.client.event(Disconnected {
self_id: self.id,
last_serial: self.client.last_serial(),
reason: error.is_some() as _,
explanation: error,
});
}
pub fn send_seat(&self, seat: &EiSeat) {
self.client.event(Seat {
self_id: self.id,
seat: seat.id,
version: seat.version.0,
});
}
pub fn announce_seat(&self, seat: &Rc<WlSeatGlobal>) {
let version = self.client.versions.ei_seat.version.get();
if version == EiVersion(0) {
return;
}
let kb_state_id = match self.context() {
EiContext::Sender => seat.seat_kb_state().borrow().id,
EiContext::Receiver => seat.latest_kb_state().borrow().id,
};
let seat = Rc::new(EiSeat {
id: self.client.new_id(),
client: self.client.clone(),
tracker: Default::default(),
version,
seat: seat.clone(),
capabilities: Cell::new(0),
kb_state_id: Cell::new(kb_state_id),
keyboard_id: self.client.state.physical_keyboard_ids.next(),
device: Default::default(),
pointer: Default::default(),
pointer_absolute: Default::default(),
keyboard: Default::default(),
button: Default::default(),
scroll: Default::default(),
touchscreen: Default::default(),
});
track!(self.client, seat);
self.client.add_server_obj(&seat);
self.send_seat(&seat);
let v = &self.client.versions;
let caps = [
(EI_CAP_POINTER, EiPointer, &v.ei_pointer),
(
EI_CAP_POINTER_ABSOLUTE,
EiPointerAbsolute,
&v.ei_pointer_absolute,
),
(EI_CAP_SCROLL, EiScroll, &v.ei_scroll),
(EI_CAP_BUTTON, EiButton, &v.ei_button),
(EI_CAP_KEYBOARD, EiKeyboard, &v.ei_keyboard),
(EI_CAP_TOUCHSCREEN, EiTouchscreen, &v.ei_touchscreen),
];
for (mask, interface, version) in caps {
if version.version.get() > EiVersion(0) {
seat.send_capability(interface, mask);
}
}
seat.send_name(&seat.seat.seat_name());
seat.send_done();
seat.seat.add_ei_seat(&seat);
}
}
impl EiConnectionRequestHandler for EiConnection {
type Error = EiConnectionError;
fn sync(
&self,
req: crate::wire_ei::ei_connection::Sync,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let version = EiVersion(req.version);
if version > self.client.versions.ei_callback.version.get() {
return Err(EiConnectionError::CallbackVersion(req.version));
}
let cb = Rc::new(EiCallback {
id: req.callback,
client: self.client.clone(),
tracker: Default::default(),
version,
});
track!(self.client, cb);
self.client.add_client_obj(&cb)?;
cb.send_done(0);
self.client.remove_obj(&*cb)?;
Ok(())
}
fn disconnect(&self, _req: Disconnect, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.disconnect_announced.set(true);
self.client.state.ei_clients.shutdown(self.client.id);
Ok(())
}
}
ei_object_base! {
self = EiConnection;
version = self.version;
}
impl EiObject for EiConnection {}
#[derive(Debug, Error)]
pub enum EiConnectionError {
#[error(transparent)]
EiClientError(Box<EiClientError>),
#[error("The callback version is too large: {0}")]
CallbackVersion(u32),
}
efrom!(EiConnectionError, EiClientError);