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
}