aboutsummaryrefslogtreecommitdiff
path: root/src/ipc/client.rs
blob: c09ef84e1a26eed54a3bfbffa25c72b2cb06625a (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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::env;
use std::io::{Read, Write};
use std::net::Shutdown;
use std::os::unix::net::UnixStream;

use anyhow::{bail, Context};
use niri_ipc::{Mode, Output, Request, Response};

use crate::Msg;

pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
    let socket_path = env::var_os(niri_ipc::SOCKET_PATH_ENV).with_context(|| {
        format!(
            "{} is not set, are you running this within niri?",
            niri_ipc::SOCKET_PATH_ENV
        )
    })?;

    let mut stream =
        UnixStream::connect(socket_path).context("error connecting to {socket_path}")?;

    let request = match msg {
        Msg::Outputs => Request::Outputs,
    };
    let mut buf = serde_json::to_vec(&request).unwrap();
    stream
        .write_all(&buf)
        .context("error writing IPC request")?;
    stream
        .shutdown(Shutdown::Write)
        .context("error closing IPC stream for writing")?;

    buf.clear();
    stream
        .read_to_end(&mut buf)
        .context("error reading IPC response")?;

    let response = serde_json::from_slice(&buf).context("error parsing IPC response")?;
    match msg {
        Msg::Outputs => {
            #[allow(irrefutable_let_patterns)]
            let Response::Outputs(outputs) = response
            else {
                bail!("unexpected response: expected Outputs, got {response:?}");
            };

            if json {
                let output =
                    serde_json::to_string(&outputs).context("error formatting response")?;
                println!("{output}");
                return Ok(());
            }

            let mut outputs = outputs.into_iter().collect::<Vec<_>>();
            outputs.sort_unstable_by(|a, b| a.0.cmp(&b.0));

            for (connector, output) in outputs.into_iter() {
                let Output {
                    name,
                    make,
                    model,
                    physical_size,
                    modes,
                    current_mode,
                } = output;

                println!(r#"Output "{connector}" ({make} - {model} - {name})"#);

                if let Some(current) = current_mode {
                    let mode = *modes
                        .get(current)
                        .context("invalid response: current mode does not exist")?;
                    let Mode {
                        width,
                        height,
                        refresh_rate,
                    } = mode;
                    let refresh = refresh_rate as f64 / 1000.;
                    println!("  Current mode: {width}x{height} @ {refresh:.3} Hz");
                } else {
                    println!("  Disabled");
                }

                if let Some((width, height)) = physical_size {
                    println!("  Physical size: {width}x{height} mm");
                } else {
                    println!("  Physical size: unknown");
                }

                println!("  Available modes:");
                for mode in modes {
                    let Mode {
                        width,
                        height,
                        refresh_rate,
                    } = mode;
                    let refresh = refresh_rate as f64 / 1000.;
                    println!("    {width}x{height}@{refresh:.3}");
                }
                println!();
            }
        }
    }

    Ok(())
}