blob: aa301ec74bf2d324bd8d2ba8f87c48616680a51a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
use serde_json::json;
use std::io::Write;
use swayipc::{Connection, Event, EventType, Fallible, Node};
/// True if this node represents an actual window (not a workspace/output/container)
fn is_window(node: &Node) -> bool {
node.app_id.is_some() || node.window_properties.is_some()
}
/// Walk the tree and find the focused node.
fn find_focused(node: &Node) -> Option<&Node> {
// Also checking for if it's a window otherwise Sway marks an empty workspace as focused
if node.focused && is_window(node) {
return Some(node);
}
node.nodes
.iter()
.chain(node.floating_nodes.iter())
.find_map(find_focused)
}
fn format_line(node: &Node) -> String {
let app_id = node
.app_id
.clone()
.or_else(|| node.window_properties.as_ref()?.class.clone())
.unwrap_or_else(|| "?".to_string());
let title = node.name.clone().unwrap_or_default();
format!("{app_id} | {title}")
}
fn print_json(text: &str) {
let escaped = json!({ "text": text, "tooltip": false });
println!("{escaped}");
let _ = std::io::stdout().flush();
}
fn main() -> Fallible<()> {
// Print current focused window immediately so waybar has something
// on startup instead of waiting for the next event.
{
let mut conn = Connection::new()?;
let tree = conn.get_tree()?;
let text = find_focused(&tree).map(format_line).unwrap_or_default();
print_json(&text);
}
// Then stream updates as they happen.
let subs = [EventType::Window, EventType::Workspace];
for event in Connection::new()?.subscribe(subs)? {
match event {
Ok(Event::Window(_)) | Ok(Event::Workspace(_)) => {
let mut conn = Connection::new()?;
let tree = conn.get_tree()?;
let text = find_focused(&tree).map(format_line).unwrap_or_default();
print_json(&text);
}
Ok(_) => {}
Err(e) => eprintln!("swayipc event error: {e}"),
}
}
Ok(())
}
|