From 0c3f87531e376824df400c6fa6a153310e249962 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Wed, 13 Jan 2021 14:58:41 +0100 Subject: [PATCH] Init --- .gitignore | 1 + Cargo.toml | 12 ++++ src/lib.rs | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 12 ++++ 4 files changed, 214 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ab636ff --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "swayr" +version = "0.0.1" +authors = ["Tassilo Horn"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.117", features = ["derive"] } +serde_json = "1.0.59" +clap = "3.0.0-beta.2" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..1569f1a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,189 @@ +extern crate serde; +extern crate serde_json; + +use serde::Deserialize; + +use std::process as proc; + +pub type Id = u32; +pub type Dim = u16; +pub type Pid = u16; + +#[derive(Deserialize)] +pub struct Rect { + x: Dim, + y: Dim, + width: Dim, + height: Dim, +} + +// TODO: Maybe there are more? +#[derive(Deserialize)] +pub enum Border { + #[serde(rename = "none")] + None, + #[serde(rename = "pixel")] + Pixel, + #[serde(rename = "csd")] + Csd, +} + +// TODO: Maybe there are more? +#[derive(Deserialize)] +pub enum Layout { + #[serde(rename = "splith")] + SplitH, + #[serde(rename = "splitv")] + SplitV, + #[serde(rename = "tabbed")] + Tabbed, + #[serde(rename = "stacked")] + Stacked, + #[serde(rename = "output")] + Output, + #[serde(rename = "none")] + None, +} + +#[derive(Deserialize)] +pub enum Orientation { + #[serde(rename = "horizontal")] + Horizontal, + #[serde(rename = "vertical")] + Vertical, + #[serde(rename = "none")] + None, +} + +#[derive(Deserialize, PartialEq)] +pub enum NodeType { + #[serde(rename = "root")] + Root, + #[serde(rename = "workspace")] + Workspace, + #[serde(rename = "output")] + Output, + #[serde(rename = "con")] + Con, + #[serde(rename = "floating_con")] + FloatingCon, +} + +#[derive(Deserialize)] +pub enum ShellType { + #[serde(rename = "xdg_shell")] + XdgShell, + #[serde(rename = "xwayland")] + XWayland, +} + +#[derive(Deserialize)] +pub struct Node { + id: Id, + name: Option, + rect: Rect, + focused: bool, + focus: Vec, + border: Border, + current_border_width: Dim, + layout: Layout, + orientation: Orientation, + percent: Option, + window_rect: Rect, + deco_rect: Rect, + geometry: Rect, + window: Option, + urgent: bool, + marks: Vec, + fullscreen_mode: u8, // TODO: actually, it's 0 or 1, i.e., a bool + nodes: Vec, + floating_nodes: Vec, + sticky: bool, + r#type: NodeType, + app_id: Option, + visible: Option, + max_render_time: Option, + pid: Option, + shell: Option, +} + +impl Node { + fn add_children<'a>(&'a self, v: &'a mut Vec<&'a Node>) { + for n in self.nodes.iter() { + v.push(&n); + n.add_children(v); + } + } + + fn iter(&self) -> NodeIter { + let mut v = vec![self]; + self.add_children(&mut v); + NodeIter { stack: v } + } +} + +struct NodeIter<'a> { + stack: Vec<&'a Node>, +} + +impl<'a> Iterator for NodeIter<'a> { + type Item = &'a Node; + + fn next(&mut self) -> Option<::Item> { + self.stack.pop() + } +} + +pub fn get_tree() -> Node { + let output = proc::Command::new("swaymsg") + .arg("-t") + .arg("get_tree") + .output() + .expect("Error running swaymsg!"); + let result = serde_json::from_str( + String::from_utf8(output.stdout) + .expect("Wrong string data!") + .as_str(), + ); + + match result { + Ok(node) => node, + Err(e) => { + eprintln!("Error: {}", e); + panic!() + } + } +} + +pub struct Con<'a> { + name: &'a str, + id: Id, + app_id: Option<&'a str>, +} + +impl<'a> std::fmt::Display for Con<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{} {}", self.name, self.app_id.unwrap_or("")) + } +} + +/// Gets all cons (aka, application windows) of the tree. +pub fn get_cons<'a>(tree: &'a Node) -> Vec> { + let mut v = vec![]; + for n in tree.iter() { + if n.r#type == NodeType::Con || n.r#type == NodeType::FloatingCon { + v.push(Con { + name: &n + .name + .as_ref() + .expect(format!("Con without name. id = {}", n.id).as_str()), + id: n.id, + app_id: match &n.app_id { + Some(s) => Some(s.as_ref()), + None => None, + }, + }) + } + } + v +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..865e775 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,12 @@ +use std::fs; +use std::io; + +use swayr::Node; + +fn main() { + let root_node = swayr::get_tree(); + for con in swayr::get_cons(&root_node) { + println!("{}\n", con); + } + println!("Yes!") +}