sway.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. use std::io::prelude::*;
  2. use std::os::unix::net::UnixStream;
  3. use std::cell::RefCell;
  4. use std::convert::AsMut;
  5. use serde::Deserialize;
  6. fn into_array<A, T>(slice: &[T]) -> A
  7. where A: Sized + Default + AsMut<[T]>,
  8. T: Clone
  9. {
  10. let mut a = Default::default();
  11. <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
  12. a
  13. }
  14. #[repr(u32)]
  15. #[allow(unused)]
  16. #[derive(Clone, Copy, Debug)]
  17. enum PacketType {
  18. RunCommand = 0,
  19. GetWorkspaces,
  20. Subscribe,
  21. GetOutputs,
  22. GetTree,
  23. GetMarks,
  24. GetBarConfig,
  25. GetVersion,
  26. GetBindingModes,
  27. GetConfig,
  28. SendTick,
  29. SyncMsg,
  30. GetBindingState,
  31. GetInputs = 100,
  32. GetSeats
  33. }
  34. const HEADER_MAGIC: [u8;6] = ['i' as u8, '3' as u8, '-' as u8, 'i' as u8, 'p' as u8, 'c' as u8];
  35. #[repr(packed)]
  36. #[derive(Clone, Copy, Debug)]
  37. struct PacketHeader {
  38. _magic: [u8;6],
  39. len: u32,
  40. _ptype: PacketType,
  41. }
  42. const PACKET_HEADER_LEN : usize = 14;
  43. impl PacketHeader {
  44. fn buffer_with_data(self, data: &str) -> Vec<u8> {
  45. let mut ret = Vec::new();
  46. let self_data = &self as *const _ as *const u8;
  47. ret.extend_from_slice(unsafe {
  48. std::slice::from_raw_parts(self_data, core::mem::size_of::<Self>())
  49. });
  50. ret.extend_from_slice(data.as_bytes());
  51. ret
  52. }
  53. fn parse(data: [u8; 14]) -> Self {
  54. 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])) } }
  55. }
  56. }
  57. pub struct SwayInterface {
  58. sock: RefCell<UnixStream>
  59. }
  60. impl SwayInterface {
  61. pub fn new() -> Self {
  62. let path = std::env::var("SWAYSOCK").expect("SWAYSOCK to be set");
  63. let sock = UnixStream::connect(path).expect("Can connect to sway socket");
  64. SwayInterface { sock: RefCell::new(sock) }
  65. }
  66. fn send_packet(&self, ptype: PacketType, data: &str) -> Result<(), std::io::Error> {
  67. let phdr = PacketHeader { _magic: HEADER_MAGIC, len: data.len() as u32, _ptype: ptype };
  68. self.sock.borrow_mut().write(&phdr.buffer_with_data(data))?;
  69. Ok(())
  70. }
  71. fn read_packet(&self) -> Result<serde_json::Value, std::io::Error> {
  72. let mut header_data = [0u8; PACKET_HEADER_LEN];
  73. self.sock.borrow_mut().read_exact(&mut header_data)?;
  74. let header = PacketHeader::parse(header_data);
  75. let mut body : Vec<u8> = Vec::new();
  76. body.resize(header.len as usize, 0);
  77. self.sock.borrow_mut().read_exact(&mut body)?;
  78. let body = std::str::from_utf8(body.as_slice()).expect("Valid unicode");
  79. let v: serde_json::Value = serde_json::from_str(body).expect("to get good JSON back from sway");
  80. Ok(v)
  81. }
  82. pub fn switch_to_workspace(&self, name: &str) -> Result<(), std::io::Error> {
  83. self.send_packet(PacketType::RunCommand, format!("workspace {}", name).as_str())?;
  84. self.read_packet()?;
  85. Ok(())
  86. }
  87. pub fn move_to_workspace(&self, name: &str) -> Result<(), std::io::Error> {
  88. self.send_packet(PacketType::RunCommand, format!("move container to workspace {}", name).as_str())?;
  89. self.read_packet()?;
  90. Ok(())
  91. }
  92. pub fn get_workspaces(&self) -> Result<Vec<Workspace>, std::io::Error> {
  93. self.send_packet(PacketType::GetWorkspaces, "")?;
  94. let response = self.read_packet()?;
  95. let ws : Vec<Workspace> = serde_json::from_value(response).expect("valid schema");
  96. Ok(ws)
  97. }
  98. pub fn get_current_workspace(&self) -> Result<String, std::io::Error> {
  99. let ws = self.get_workspaces()?;
  100. for w in ws {
  101. if w.focused { return Ok(w.name) }
  102. }
  103. unreachable!("At least one workspace will be focused");
  104. }
  105. }
  106. #[derive(Deserialize)]
  107. pub struct Workspace {
  108. id: u32,
  109. pub name: String,
  110. focused: bool
  111. }