parent
c060d05a23
commit
a4a435de54
4 changed files with 229 additions and 219 deletions
@ -0,0 +1,47 @@ |
||||
use crate::ipc; |
||||
|
||||
#[allow(dead_code)] |
||||
pub struct Con<'a> { |
||||
name: &'a str, |
||||
id: ipc::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.app_id.unwrap_or(""), self.name) |
||||
} |
||||
} |
||||
|
||||
/// Gets all cons (aka, application windows) of the tree.
|
||||
pub fn get_cons<'a>(tree: &'a ipc::Node) -> Vec<Con<'a>> { |
||||
let mut v = vec![]; |
||||
for n in tree.iter() { |
||||
if n.r#type == ipc::NodeType::Con || n.r#type == ipc::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 |
||||
} |
||||
|
||||
#[test] |
||||
fn test_get_cons() { |
||||
let tree = ipc::get_tree(); |
||||
let cons = get_cons(&tree); |
||||
|
||||
println!("There are {} cons.", cons.len()); |
||||
|
||||
for c in cons { |
||||
println!(" {}", c); |
||||
} |
||||
} |
@ -0,0 +1,175 @@ |
||||
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)] |
||||
#[allow(dead_code)] |
||||
pub struct Rect { |
||||
pub x: Dim, |
||||
pub y: Dim, |
||||
pub width: Dim, |
||||
pub 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, Debug)] |
||||
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)] |
||||
#[allow(dead_code)] |
||||
pub struct Node { |
||||
pub id: Id, |
||||
pub name: Option<String>, |
||||
pub rect: Rect, |
||||
pub focused: bool, |
||||
pub focus: Vec<Id>, |
||||
pub border: Border, |
||||
pub current_border_width: Dim, |
||||
pub layout: Layout, |
||||
pub orientation: Orientation, |
||||
pub percent: Option<f64>, |
||||
pub window_rect: Rect, |
||||
pub deco_rect: Rect, |
||||
pub geometry: Rect, |
||||
pub window: Option<Id>, |
||||
pub urgent: bool, |
||||
pub marks: Vec<String>, |
||||
pub fullscreen_mode: u8, // TODO: actually, it's 0 or 1, i.e., a bool
|
||||
pub nodes: Vec<Node>, |
||||
pub floating_nodes: Vec<Node>, |
||||
pub sticky: bool, |
||||
pub r#type: NodeType, |
||||
pub app_id: Option<String>, |
||||
pub visible: Option<bool>, |
||||
pub max_render_time: Option<i32>, |
||||
pub pid: Option<Pid>, |
||||
pub shell: Option<ShellType>, |
||||
} |
||||
|
||||
impl Node { |
||||
pub fn iter(&self) -> PreOrderNodeIter { |
||||
PreOrderNodeIter::new(self) |
||||
} |
||||
} |
||||
|
||||
pub struct PreOrderNodeIter<'a> { |
||||
stack: Vec<&'a Node>, |
||||
} |
||||
|
||||
impl<'a> PreOrderNodeIter<'a> { |
||||
fn new(node: &'a Node) -> PreOrderNodeIter { |
||||
PreOrderNodeIter { stack: vec![node] } |
||||
} |
||||
} |
||||
|
||||
impl<'a> Iterator for PreOrderNodeIter<'a> { |
||||
type Item = &'a Node; |
||||
|
||||
fn next(&mut self) -> Option<Self::Item> { |
||||
if let Some(node) = self.stack.pop() { |
||||
for n in &node.floating_nodes { |
||||
self.stack.push(&n); |
||||
} |
||||
for n in &node.nodes { |
||||
self.stack.push(&n); |
||||
} |
||||
Some(node) |
||||
} else { |
||||
None |
||||
} |
||||
} |
||||
} |
||||
|
||||
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!() |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[test] |
||||
fn test_get_tree() { |
||||
let tree = get_tree(); |
||||
|
||||
println!("Those IDs are in get_tree():"); |
||||
for n in tree.iter() { |
||||
println!(" id: {}, type: {:?}", n.id, n.r#type); |
||||
} |
||||
} |
@ -1,217 +1,2 @@ |
||||
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)] |
||||
#[allow(dead_code)] |
||||
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)] |
||||
#[allow(dead_code)] |
||||
pub struct Node { |
||||
id: Id, |
||||
name: Option<String>, |
||||
rect: Rect, |
||||
focused: bool, |
||||
focus: Vec<Id>, |
||||
border: Border, |
||||
current_border_width: Dim, |
||||
layout: Layout, |
||||
orientation: Orientation, |
||||
percent: Option<f64>, |
||||
window_rect: Rect, |
||||
deco_rect: Rect, |
||||
geometry: Rect, |
||||
window: Option<Id>, |
||||
urgent: bool, |
||||
marks: Vec<String>, |
||||
fullscreen_mode: u8, // TODO: actually, it's 0 or 1, i.e., a bool
|
||||
nodes: Vec<Node>, |
||||
floating_nodes: Vec<Node>, |
||||
sticky: bool, |
||||
r#type: NodeType, |
||||
app_id: Option<String>, |
||||
visible: Option<bool>, |
||||
max_render_time: Option<i32>, |
||||
pid: Option<Pid>, |
||||
shell: Option<ShellType>, |
||||
} |
||||
|
||||
impl Node { |
||||
fn iter(&self) -> PreOrderNodeIter { |
||||
PreOrderNodeIter::new(self) |
||||
} |
||||
} |
||||
|
||||
struct PreOrderNodeIter<'a> { |
||||
stack: Vec<&'a Node>, |
||||
} |
||||
|
||||
impl<'a> PreOrderNodeIter<'a> { |
||||
fn new(node: &'a Node) -> PreOrderNodeIter { |
||||
PreOrderNodeIter { stack: vec![node] } |
||||
} |
||||
} |
||||
|
||||
impl<'a> Iterator for PreOrderNodeIter<'a> { |
||||
type Item = &'a Node; |
||||
|
||||
fn next(&mut self) -> Option<Self::Item> { |
||||
if let Some(node) = self.stack.pop() { |
||||
for n in &node.nodes { |
||||
self.stack.push(&n); |
||||
} |
||||
for n in &node.floating_nodes { |
||||
self.stack.push(&n); |
||||
} |
||||
Some(node) |
||||
} else { |
||||
None |
||||
} |
||||
} |
||||
} |
||||
|
||||
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!() |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[allow(dead_code)] |
||||
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.app_id.unwrap_or(""), self.name) |
||||
} |
||||
} |
||||
|
||||
/// Gets all cons (aka, application windows) of the tree.
|
||||
pub fn get_cons<'a>(tree: &'a Node) -> Vec<Con<'a>> { |
||||
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 |
||||
} |
||||
|
||||
#[test] |
||||
fn test_get_cons() { |
||||
let tree = get_tree(); |
||||
|
||||
println!("Those IDs are in get_tree():"); |
||||
for n in tree.iter() { |
||||
println!(" id: {}", n.id); |
||||
} |
||||
|
||||
let cons = get_cons(&tree); |
||||
|
||||
println!("There are {} cons.", cons.len()); |
||||
|
||||
for c in cons { |
||||
println!("{}", c); |
||||
} |
||||
} |
||||
pub mod con; |
||||
pub mod ipc; |
||||
|
Loading…
Reference in new issue