i3status_rs/blocks/
scratchpad.rs

1//! Scratchpad indicator
2//!
3//! # Configuration
4//!
5//! Key | Values | Default
6//! ----|--------|--------
7//! `format`          | A string to customise the output of this block | ` $icon $count.eng(range:1..) |`
8//!
9//! Placeholder | Value                                      | Type   | Unit
10//! ------------|--------------------------------------------|--------|-----
11//! `icon`      | A static icon                              | Icon   | -
12//! `count`     | Number of windows in scratchpad            | Number | -
13//!
14//! # Example
15//!
16//! ```toml
17//! [[block]]
18//! block = "scratchpad"
19//! ```
20//!
21//! # Icons Used
22//! - `scratchpad`
23
24use swayipc_async::{Connection, Event as SwayEvent, EventType, Node, WindowChange};
25
26use super::prelude::*;
27
28#[derive(Deserialize, Debug, SmartDefault)]
29#[serde(deny_unknown_fields, default)]
30pub struct Config {
31    pub format: FormatConfig,
32}
33
34fn count_scratchpad_windows(node: &Node) -> usize {
35    node.find_as_ref(|n| n.name.as_deref() == Some("__i3_scratch"))
36        .map_or(0, |node| node.floating_nodes.len())
37}
38
39pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
40    let format = config
41        .format
42        .with_default(" $icon $count.eng(range:1..) |")?;
43
44    let connection_for_events = Connection::new()
45        .await
46        .error("failed to open connection with swayipc")?;
47
48    let mut connection_for_tree = Connection::new()
49        .await
50        .error("failed to open connection with swayipc")?;
51
52    let mut events = connection_for_events
53        .subscribe(&[EventType::Window])
54        .await
55        .error("could not subscribe to window events")?;
56
57    loop {
58        let mut widget = Widget::new().with_format(format.clone());
59
60        let root_node = connection_for_tree
61            .get_tree()
62            .await
63            .error("could not get windows tree")?;
64        let count = count_scratchpad_windows(&root_node);
65
66        widget.set_values(map! {
67            "icon" => Value::icon("scratchpad"),
68            "count" => Value::number(count),
69        });
70
71        api.set_widget(widget)?;
72
73        loop {
74            let event = events
75                .next()
76                .await
77                .error("swayipc channel closed")?
78                .error("bad event")?;
79
80            match event {
81                SwayEvent::Window(e) if e.change == WindowChange::Move => break,
82                _ => continue,
83            }
84        }
85    }
86}