mod handler; use { crate::{ backend::{ConnectorId, InputDeviceId}, config::handler::ConfigProxyHandler, ifs::wl_seat::SeatId, state::State, utils::{numcell::NumCell, ptr_ext::PtrExt}, }, jay_config::{ _private::{ bincode_ops, ipc::{InitMessage, ServerMessage, V1InitMessage}, ConfigEntry, VERSION, }, drm::Connector, input::{InputDevice, Seat}, keyboard::ModifiedKeySym, }, libloading::Library, std::{cell::Cell, mem, ptr, rc::Rc}, thiserror::Error, }; #[derive(Debug, Error)] pub enum ConfigError { #[error("Could not load the config library")] CouldNotLoadLibrary(#[source] libloading::Error), #[error("Config library does not contain the entry symbol")] LibraryDoesNotContainEntry(#[source] libloading::Error), } pub struct ConfigProxy { handler: Rc, } impl ConfigProxy { pub fn invoke_shortcut(&self, seat: SeatId, modsym: &ModifiedKeySym) { self.handler.send(&ServerMessage::InvokeShortcut { seat: Seat(seat.raw() as _), mods: modsym.mods, sym: modsym.sym, }); } pub fn new_connector(&self, connector: ConnectorId) { self.handler.send(&ServerMessage::NewConnector { device: Connector(connector.raw() as _), }); } pub fn del_connector(&self, connector: ConnectorId) { self.handler.send(&ServerMessage::DelConnector { device: Connector(connector.raw() as _), }); } pub fn connector_connected(&self, connector: ConnectorId) { self.handler.send(&ServerMessage::ConnectorConnect { device: Connector(connector.raw() as _), }); } pub fn connector_disconnected(&self, connector: ConnectorId) { self.handler.send(&ServerMessage::ConnectorDisconnect { device: Connector(connector.raw() as _), }); } pub fn new_input_device(&self, dev: InputDeviceId) { self.handler.send(&ServerMessage::NewInputDevice { device: InputDevice(dev.raw() as _), }); } pub fn del_input_device(&self, dev: InputDeviceId) { self.handler.send(&ServerMessage::DelInputDevice { device: InputDevice(dev.raw() as _), }); } pub fn graphics_initialized(&self) { self.handler.send(&ServerMessage::GraphicsInitialized); } } impl Drop for ConfigProxy { fn drop(&mut self) { unsafe { self.handler.do_drop(); (self.handler.unref)(self.handler.client_data.get()); } } } unsafe extern "C" fn default_client_init( srv_data: *const u8, srv_unref: unsafe extern "C" fn(data: *const u8), srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize), msg: *const u8, size: usize, ) -> *const u8 { extern "C" fn configure() { default_config::configure(); } jay_config::_private::client::init(srv_data, srv_unref, srv_handler, msg, size, configure) } impl ConfigProxy { fn new(lib: Option, entry: &ConfigEntry, state: &Rc) -> Self { let version = entry.version.min(VERSION); let data = Rc::new(ConfigProxyHandler { client_data: Cell::new(ptr::null()), dropped: Cell::new(false), _lib: lib, _version: version, unref: entry.unref, handle_msg: entry.handle_msg, state: state.clone(), next_id: NumCell::new(1), keymaps: Default::default(), bufs: Default::default(), workspace_ids: NumCell::new(1), workspaces_by_name: Default::default(), workspaces_by_id: Default::default(), timer_ids: NumCell::new(1), timers_by_name: Default::default(), timers_by_id: Default::default(), }); let init_msg = bincode::encode_to_vec(&InitMessage::V1(V1InitMessage {}), bincode_ops()).unwrap(); unsafe { let client_data = (entry.init)( Rc::into_raw(data.clone()) as _, unref, handle_msg, init_msg.as_ptr(), init_msg.len(), ); data.client_data.set(client_data); } data.send(&ServerMessage::Configure); Self { handler: data } } pub fn default(state: &Rc) -> Self { let entry = ConfigEntry { version: VERSION, init: default_client_init, unref: jay_config::_private::client::unref, handle_msg: jay_config::_private::client::handle_msg, }; Self::new(None, &entry, state) } #[allow(dead_code)] pub unsafe fn from_file(path: &str, state: &Rc) -> Result { let lib = match Library::new(path) { Ok(l) => l, Err(e) => return Err(ConfigError::CouldNotLoadLibrary(e)), }; let entry = lib.get::<&'static ConfigEntry>(b"I4_CONFIG_ENTRY\0"); let entry = match entry { Ok(e) => *e, Err(e) => return Err(ConfigError::LibraryDoesNotContainEntry(e)), }; Ok(Self::new(Some(lib), entry, state)) } } unsafe extern "C" fn unref(data: *const u8) { let server = data as *const ConfigProxyHandler; drop(Rc::from_raw(server)); } unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) { let server = (data as *const ConfigProxyHandler).deref(); if server.dropped.get() { return; } let rc = Rc::from_raw(server); let msg = std::slice::from_raw_parts(msg, size); rc.handle_request(msg); mem::forget(rc); }