use std::io::prelude::*; use std::os::unix::net::UnixStream; use std::cell::RefCell; use std::convert::AsMut; use serde::Deserialize; fn into_array(slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone { let mut a = Default::default(); >::as_mut(&mut a).clone_from_slice(slice); a } #[repr(u32)] #[allow(unused)] #[derive(Clone, Copy, Debug)] enum PacketType { RunCommand = 0, GetWorkspaces, Subscribe, GetOutputs, GetTree, GetMarks, GetBarConfig, GetVersion, GetBindingModes, GetConfig, SendTick, SyncMsg, GetBindingState, GetInputs = 100, GetSeats } const HEADER_MAGIC: [u8;6] = ['i' as u8, '3' as u8, '-' as u8, 'i' as u8, 'p' as u8, 'c' as u8]; #[repr(packed)] #[derive(Clone, Copy, Debug)] struct PacketHeader { _magic: [u8;6], len: u32, _ptype: PacketType, } const PACKET_HEADER_LEN : usize = 14; impl PacketHeader { fn buffer_with_data(self, data: &str) -> Vec { let mut ret = Vec::new(); let self_data = &self as *const _ as *const u8; ret.extend_from_slice(unsafe { std::slice::from_raw_parts(self_data, core::mem::size_of::()) }); ret.extend_from_slice(data.as_bytes()); ret } fn parse(data: [u8; 14]) -> Self { Self { _magic: into_array(&data[0..6]), len: unsafe { std::mem::transmute::<[u8;4], u32>(into_array(&data[6..10])) }, _ptype: unsafe { std::mem::transmute::<[u8;4], PacketType>(into_array(&data[10..14])) } } } } pub struct SwayInterface { sock: RefCell } impl SwayInterface { pub fn new() -> Self { let path = std::env::var("SWAYSOCK").expect("SWAYSOCK to be set"); let sock = UnixStream::connect(path).expect("Can connect to sway socket"); SwayInterface { sock: RefCell::new(sock) } } fn send_packet(&self, ptype: PacketType, data: &str) -> Result<(), std::io::Error> { let phdr = PacketHeader { _magic: HEADER_MAGIC, len: data.len() as u32, _ptype: ptype }; self.sock.borrow_mut().write(&phdr.buffer_with_data(data))?; Ok(()) } fn read_packet(&self) -> Result { let mut header_data = [0u8; PACKET_HEADER_LEN]; self.sock.borrow_mut().read_exact(&mut header_data)?; let header = PacketHeader::parse(header_data); let mut body : Vec = Vec::new(); body.resize(header.len as usize, 0); self.sock.borrow_mut().read_exact(&mut body)?; let body = std::str::from_utf8(body.as_slice()).expect("Valid unicode"); let v: serde_json::Value = serde_json::from_str(body).expect("to get good JSON back from sway"); Ok(v) } pub fn switch_to_workspace(&self, name: &str) -> Result<(), std::io::Error> { self.send_packet(PacketType::RunCommand, format!("workspace {}", name).as_str())?; self.read_packet()?; Ok(()) } pub fn move_to_workspace(&self, name: &str) -> Result<(), std::io::Error> { self.send_packet(PacketType::RunCommand, format!("move container to workspace {}", name).as_str())?; self.read_packet()?; Ok(()) } pub fn get_workspaces(&self) -> Result, std::io::Error> { self.send_packet(PacketType::GetWorkspaces, "")?; let response = self.read_packet()?; let ws : Vec = serde_json::from_value(response).expect("valid schema"); Ok(ws) } pub fn get_current_workspace(&self) -> Result { let ws = self.get_workspaces()?; for w in ws { if w.focused { return Ok(w.name) } } unreachable!("At least one workspace will be focused"); } } #[derive(Deserialize)] pub struct Workspace { id: u32, pub name: String, focused: bool }