#![allow(clippy::declare_interior_mutable_const, clippy::type_complexity)] use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; use crate::drm::connector_type::{ConnectorType, CON_UNKNOWN}; use crate::drm::{Connector, Mode}; use crate::input::acceleration::AccelProfile; use crate::input::capability::Capability; use crate::input::{InputDevice, Seat}; use crate::keyboard::keymap::Keymap; use crate::theme::Color; use crate::{Axis, Command, Direction, LogLevel, ModifiedKeySym, Workspace}; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::collections::HashMap; use std::ops::Deref; use std::rc::Rc; use std::{ptr, slice}; pub(crate) struct Client { configure: extern "C" fn(), 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), key_handlers: RefCell>>, response: RefCell>, on_new_seat: RefCell>>, on_new_input_device: RefCell>>, on_connector_connected: RefCell>>, on_new_connector: RefCell>>, bufs: RefCell>>, } impl Drop for Client { fn drop(&mut self) { unsafe { (self.srv_unref)(self.srv_data); } } } thread_local! { pub(crate) static CLIENT: std::cell::Cell<*const Client> = const { std::cell::Cell::new(ptr::null()) }; } unsafe fn with_client T>(data: *const u8, f: F) -> T { struct Reset<'a> { cell: &'a Cell<*const Client>, val: *const Client, } impl Drop for Reset<'_> { fn drop(&mut self) { self.cell.set(self.val); } } CLIENT.with(|cell| unsafe { let client = data as *const Client; Rc::increment_strong_count(client); let client = Rc::from_raw(client); let old = cell.replace(client.deref()); let _reset = Reset { cell, val: old }; f(&client) }) } impl ConfigEntryGen { pub const ENTRY: ConfigEntry = ConfigEntry { version: VERSION, init: Self::init, unref, handle_msg, }; pub unsafe extern "C" fn 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), init_data: *const u8, size: usize, ) -> *const u8 { logging::init(); init( srv_data, srv_unref, srv_handler, init_data, size, T::configure, ) } } pub unsafe extern "C" fn 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), init: *const u8, size: usize, f: extern "C" fn(), ) -> *const u8 { let client = Rc::new(Client { configure: f, srv_data, srv_unref, srv_handler, key_handlers: Default::default(), response: Default::default(), on_new_seat: Default::default(), on_new_input_device: Default::default(), on_connector_connected: Default::default(), on_new_connector: Default::default(), bufs: Default::default(), }); let init = slice::from_raw_parts(init, size); client.handle_init_msg(init); Rc::into_raw(client) as *const u8 } pub unsafe extern "C" fn unref(data: *const u8) { let client = data as *const Client; drop(Rc::from_raw(client)); } pub unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) { with_client(data, |client| { let msg = slice::from_raw_parts(msg, size); client.handle_msg(msg); }); } macro_rules! get_response { ($res:expr, $def:expr, $ty:ident, $($field:ident),+) => { let ($($field,)+) = match $res { Response::$ty { $($field,)+ } => ($($field,)+), _ => { log::error!("Server did not send a response to a {} request", stringify!($ty)); return $def; } }; } } impl Client { fn send(&self, msg: &ClientMessage) { let mut buf = self.bufs.borrow_mut().pop().unwrap_or_default(); buf.clear(); bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap(); unsafe { (self.srv_handler)(self.srv_data, buf.as_ptr(), buf.len()); } self.bufs.borrow_mut().push(buf); } fn send_with_response(&self, msg: &ClientMessage) -> Response { self.with_response(|| self.send(msg)) } pub fn spawn(&self, command: &Command) { let env = command .env .iter() .map(|(a, b)| (a.to_string(), b.to_string())) .collect(); self.send(&ClientMessage::Run { prog: &command.prog, args: command.args.clone(), env, }); } pub fn grab(&self, kb: InputDevice, grab: bool) { self.send(&ClientMessage::GrabKb { kb, grab }); } pub fn focus(&self, seat: Seat, direction: Direction) { self.send(&ClientMessage::Focus { seat, direction }); } pub fn move_(&self, seat: Seat, direction: Direction) { self.send(&ClientMessage::Move { seat, direction }); } pub fn unbind>(&self, seat: Seat, mod_sym: T) { let mod_sym = mod_sym.into(); let deregister = self .key_handlers .borrow_mut() .remove(&(seat, mod_sym)) .is_some(); if deregister { self.send(&ClientMessage::RemoveShortcut { seat, mods: mod_sym.mods, sym: mod_sym.sym, }) } } fn with_response(&self, f: F) -> Response { f(); self.response.borrow_mut().pop().unwrap_or(Response::None) } pub fn seats(&self) -> Vec { let res = self.with_response(|| self.send(&ClientMessage::GetSeats)); get_response!(res, vec![], GetSeats, seats); seats } pub fn mono(&self, seat: Seat) -> bool { let res = self.with_response(|| self.send(&ClientMessage::GetMono { seat })); get_response!(res, false, GetMono, mono); mono } pub fn get_workspace(&self, name: &str) -> Workspace { let res = self.with_response(|| self.send(&ClientMessage::GetWorkspace { name })); get_response!(res, Workspace(0), GetWorkspace, workspace); workspace } pub fn get_connector(&self, ty: ConnectorType, idx: u32) -> Connector { let res = self.with_response(|| self.send(&ClientMessage::GetConnector { ty, idx })); get_response!(res, Connector(0), GetConnector, connector); connector } pub fn show_workspace(&self, seat: Seat, workspace: Workspace) { self.send(&ClientMessage::ShowWorkspace { seat, workspace }); } pub fn split(&self, seat: Seat) -> Axis { let res = self.with_response(|| self.send(&ClientMessage::GetSplit { seat })); get_response!(res, Axis::Horizontal, GetSplit, axis); axis } pub fn toggle_floating(&self, seat: Seat) { self.send(&ClientMessage::ToggleFloating { seat }); } pub fn set_title_color(&self, color: Color) { self.send(&ClientMessage::SetTitleColor { color }); } pub fn set_border_color(&self, color: Color) { self.send(&ClientMessage::SetBorderColor { color }); } pub fn set_title_underline_color(&self, color: Color) { self.send(&ClientMessage::SetTitleUnderlineColor { color }); } pub fn set_background_color(&self, color: Color) { self.send(&ClientMessage::SetBackgroundColor { color }); } pub fn get_title_height(&self) -> i32 { let res = self.with_response(|| self.send(&ClientMessage::GetTitleHeight)); get_response!(res, 0, GetTitleHeight, height); height } pub fn get_border_width(&self) -> i32 { let res = self.with_response(|| self.send(&ClientMessage::GetBorderWidth)); get_response!(res, 0, GetBorderWidth, width); width } pub fn set_title_height(&self, height: i32) { self.send(&ClientMessage::SetTitleHeight { height }) } pub fn set_border_width(&self, width: i32) { self.send(&ClientMessage::SetBorderWidth { width }) } pub fn set_mono(&self, seat: Seat, mono: bool) { self.send(&ClientMessage::SetMono { seat, mono }); } pub fn set_split(&self, seat: Seat, axis: Axis) { self.send(&ClientMessage::SetSplit { seat, axis }); } pub fn create_split(&self, seat: Seat, axis: Axis) { self.send(&ClientMessage::CreateSplit { seat, axis }); } pub fn focus_parent(&self, seat: Seat) { self.send(&ClientMessage::FocusParent { seat }); } pub fn create_seat(&self, name: &str) -> Seat { let res = self.with_response(|| self.send(&ClientMessage::CreateSeat { name })); get_response!(res, Seat(0), CreateSeat, seat); seat } pub fn get_input_devices(&self, seat: Option) -> Vec { let res = self.with_response(|| self.send(&ClientMessage::GetInputDevices { seat })); get_response!(res, vec!(), GetInputDevices, devices); devices } pub fn on_new_seat(&self, f: F) { *self.on_new_seat.borrow_mut() = Some(Rc::new(f)); } pub fn quit(&self) { self.send(&ClientMessage::Quit) } pub fn switch_to_vt(&self, vtnr: u32) { self.send(&ClientMessage::SwitchTo { vtnr }) } pub fn on_new_input_device(&self, f: F) { *self.on_new_input_device.borrow_mut() = Some(Rc::new(f)); } pub fn connector_set_position(&self, connector: Connector, x: i32, y: i32) { self.send(&ClientMessage::ConnectorSetPosition { connector, x, y }); } pub fn connector_connected(&self, connector: Connector) -> bool { let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector }); get_response!(res, false, ConnectorConnected, connected); connected } pub fn connector_type(&self, connector: Connector) -> ConnectorType { let res = self.send_with_response(&ClientMessage::ConnectorType { connector }); get_response!(res, CON_UNKNOWN, ConnectorType, ty); ty } pub fn connector_mode(&self, connector: Connector) -> Mode { let res = self.send_with_response(&ClientMessage::ConnectorMode { connector }); get_response!( res, Mode::zeroed(), ConnectorMode, width, height, refresh_millihz ); Mode { width, height, refresh_millihz, } } pub fn on_new_connector(&self, f: F) { *self.on_new_connector.borrow_mut() = Some(Rc::new(f)); } pub fn on_connector_connected(&self, f: F) { *self.on_connector_connected.borrow_mut() = Some(Rc::new(f)); } pub fn set_seat(&self, device: InputDevice, seat: Seat) { self.send(&ClientMessage::SetSeat { device, seat }) } pub fn set_left_handed(&self, device: InputDevice, left_handed: bool) { self.send(&ClientMessage::SetLeftHanded { device, left_handed, }) } pub fn set_accel_profile(&self, device: InputDevice, profile: AccelProfile) { self.send(&ClientMessage::SetAccelProfile { device, profile }) } pub fn set_accel_speed(&self, device: InputDevice, speed: f64) { self.send(&ClientMessage::SetAccelSpeed { device, speed }) } pub fn set_transform_matrix(&self, device: InputDevice, matrix: [[f64; 2]; 2]) { self.send(&ClientMessage::SetTransformMatrix { device, matrix }) } pub fn device_name(&self, device: InputDevice) -> String { let res = self.with_response(|| self.send(&ClientMessage::GetDeviceName { device })); get_response!(res, String::new(), GetDeviceName, name); name } pub fn has_capability(&self, device: InputDevice, cap: Capability) -> bool { let res = self.with_response(|| self.send(&ClientMessage::HasCapability { device, cap })); get_response!(res, false, HasCapability, has); has } pub fn seat_set_keymap(&self, seat: Seat, keymap: Keymap) { self.send(&ClientMessage::SeatSetKeymap { seat, keymap }) } pub fn seat_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) { self.send(&ClientMessage::SeatSetRepeatRate { seat, rate, delay }) } pub fn seat_get_repeat_rate(&self, seat: Seat) -> (i32, i32) { let res = self.with_response(|| self.send(&ClientMessage::SeatGetRepeatRate { seat })); get_response!(res, (25, 250), GetRepeatRate, rate, delay); (rate, delay) } pub fn parse_keymap(&self, keymap: &str) -> Keymap { let res = self.with_response(|| self.send(&ClientMessage::ParseKeymap { keymap })); get_response!(res, Keymap(0), ParseKeymap, keymap); keymap } pub fn bind, F: Fn() + 'static>(&self, seat: Seat, mod_sym: T, f: F) { let mod_sym = mod_sym.into(); let register = { let mut kh = self.key_handlers.borrow_mut(); let f = Rc::new(f); match kh.entry((seat, mod_sym)) { Entry::Occupied(mut o) => { *o.get_mut() = f; false } Entry::Vacant(v) => { v.insert(f); true } } }; if register { self.send(&ClientMessage::AddShortcut { seat, mods: mod_sym.mods, sym: mod_sym.sym, }); } } pub fn log(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option) { self.send(&ClientMessage::Log { level, msg, file, line, }) } fn handle_msg(&self, msg: &[u8]) { let res = bincode::decode_from_slice::(msg, bincode_ops()); let (msg, _) = match res { Ok(msg) => msg, Err(e) => { let msg = format!("could not deserialize message: {}", e); self.log(LogLevel::Error, &msg, None, None); return; } }; match msg { ServerMessage::Configure => { (self.configure)(); } ServerMessage::Response { response } => { self.response.borrow_mut().push(response); } ServerMessage::InvokeShortcut { seat, mods, sym } => { let ms = ModifiedKeySym { mods, sym }; let handler = self.key_handlers.borrow_mut().get(&(seat, ms)).cloned(); if let Some(handler) = handler { handler(); } } ServerMessage::NewInputDevice { device } => { let handler = self.on_new_input_device.borrow_mut().clone(); if let Some(handler) = handler { handler(device); } } ServerMessage::DelInputDevice { .. } => {} ServerMessage::ConnectorConnect { device } => { let handler = self.on_connector_connected.borrow_mut().clone(); if let Some(handler) = handler { handler(device); } } ServerMessage::ConnectorDisconnect { .. } => {} ServerMessage::NewConnector { device } => { let handler = self.on_new_connector.borrow_mut().clone(); if let Some(handler) = handler { handler(device); } } ServerMessage::DelConnector { .. } => {} } } fn handle_init_msg(&self, msg: &[u8]) { let (init, _) = match bincode::decode_from_slice::(msg, bincode_ops()) { Ok(m) => m, Err(e) => { let msg = format!("could not deserialize message: {}", e); self.log(LogLevel::Error, &msg, None, None); return; } }; match init { InitMessage::V1(_) => {} } } }