summaryrefslogtreecommitdiff
path: root/waybar-window/src/main.rs
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(())
}