i3_ipc/
lib.rs

1//! # i3-ipc
2//!
3//! Subscribing to events is easy:
4//!
5//! ```no_run
6//! use i3_ipc::{
7//!     event::{Event, Subscribe},
8//!     I3Stream,
9//! };
10//! use std::io;
11//!
12//! fn main() -> io::Result<()> {
13//!     let mut i3 = I3Stream::conn_sub(&[Subscribe::Window, Subscribe::Workspace])?;
14//!     for e in i3.listen() {
15//!         match e? {
16//!             Event::Workspace(ev) => println!("workspace change event {:?}", ev),
17//!             Event::Window(ev) => println!("window event {:?}", ev),
18//!             Event::Output(ev) => println!("output event {:?}", ev),
19//!             Event::Mode(ev) => println!("mode event {:?}", ev),
20//!             Event::BarConfig(ev) => println!("bar config update {:?}", ev),
21//!             Event::Binding(ev) => println!("binding event {:?}", ev),
22//!             Event::Shutdown(ev) => println!("shutdown event {:?}", ev),
23//!             Event::Tick(ev) => println!("tick event {:?}", ev),
24//!         }
25//!     }
26//!     Ok(())
27//! }
28//! ```
29//!
30//! Getting information is equally easy, use any `get_*` method or `run_command`
31//! to send a message to i3:
32//!
33//! ```no_run
34//! use i3_ipc::{Connect, I3};
35//! use std::io;
36//!
37//! fn main() -> io::Result<()> {
38//!     let mut i3 = I3::connect()?;
39//!     let workspaces = i3.get_workspaces()?;
40//!     println!("{:?}", workspaces);
41//!     Ok(())
42//! }
43//! ```
44
45pub use i3ipc_types::*;
46
47use serde::de::DeserializeOwned;
48
49use std::{
50    io::{self, Read, Write},
51    os::unix::net::UnixStream,
52};
53
54/// Our connection type, we implement `Connect` for this
55pub struct I3;
56
57/// `I3Stream` will hold the underlying UnixStream that communicates with i3
58#[derive(Debug)]
59pub struct I3Stream(UnixStream);
60
61impl I3IPC for I3Stream {}
62impl I3Protocol for I3Stream {}
63
64/// Provides the `connect` method for `I3`
65impl Connect for I3 {
66    type Stream = I3Stream;
67
68    fn connect() -> io::Result<I3Stream> {
69        Ok(I3Stream(UnixStream::connect(socket_path()?)?))
70    }
71}
72
73impl I3Stream {
74    /// Connect & subscribe in one method
75    pub fn conn_sub<E>(events: E) -> io::Result<Self>
76    where
77        E: AsRef<[event::Subscribe]>,
78    {
79        let mut i3 = I3::connect()?;
80        i3.subscribe(events)?;
81        Ok(i3)
82    }
83
84    /// sends a subscribe message to i3 with a json encoded array of types of
85    /// events to listen to
86    pub fn subscribe<E>(&mut self, events: E) -> io::Result<reply::Success>
87    where
88        E: AsRef<[event::Subscribe]>,
89    {
90        let sub_json = serde_json::to_string(events.as_ref())?;
91        self.send_msg(msg::Msg::Subscribe, sub_json)?;
92        let resp: MsgResponse<reply::Success> = self.receive_msg()?;
93        Ok(resp.body)
94    }
95
96    /// Returns a type that implements `Iterator`, allowing us to listen to
97    /// events
98    pub fn listen(&'_ mut self) -> I3Iter<'_> {
99        I3Iter { stream: self }
100    }
101
102    /// same as `listen`
103    pub fn iter(&'_ mut self) -> I3Iter<'_> {
104        I3Iter { stream: self }
105    }
106
107    /// Send a message and payload, used for `get_*` commands and `run_command`
108    pub fn send_msg<P>(&mut self, msg: msg::Msg, payload: P) -> io::Result<usize>
109    where
110        P: AsRef<str>,
111    {
112        let buf = self.encode_msg_body(msg, payload);
113        self.write(&buf[..])
114    }
115
116    /// Receive some message from the socket. Holds a `Msg` type and payload
117    pub fn receive_msg<D: DeserializeOwned>(&mut self) -> io::Result<MsgResponse<D>> {
118        let (msg_type, payload_bytes) = self.decode_msg()?;
119        MsgResponse::new(msg_type, payload_bytes)
120    }
121
122    /// Like `receive_msg` but for `event::Event`
123    pub fn receive_event(&mut self) -> io::Result<event::Event> {
124        let (evt_type, payload_bytes) = self.decode_msg()?;
125        decode_event(evt_type, payload_bytes)
126    }
127
128    /// Send a `Msg` and payload and receive a response. Convenience function
129    /// over `send_msg` and `receive_msg`
130    pub fn send_receive<P, D>(&mut self, msg: msg::Msg, payload: P) -> io::Result<MsgResponse<D>>
131    where
132        P: AsRef<str>,
133        D: DeserializeOwned,
134    {
135        self.send_msg(msg, payload)?;
136        self.receive_msg()
137    }
138
139    /// Run an arbitrary command on i3.
140    pub fn run_command<S: AsRef<str>>(&mut self, payload: S) -> io::Result<Vec<reply::Success>> {
141        self.send_msg(msg::Msg::RunCommand, payload)?;
142        Ok(self.receive_msg()?.body)
143    }
144
145    /// Get active workspaces
146    pub fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
147        let buf = self.encode_msg(msg::Msg::Workspaces);
148        self.write_all(&buf[..])?;
149        let resp: MsgResponse<Vec<reply::Workspace>> = self.receive_msg()?;
150        Ok(resp.body)
151    }
152
153    /// Get active workspaces
154    pub fn get_outputs(&mut self) -> io::Result<reply::Outputs> {
155        // self.send_msg(msg::Msg::Outputs, "")?;
156        let buf = self.encode_msg(msg::Msg::Outputs);
157        self.write_all(&buf[..])?;
158        Ok(self.receive_msg()?.body)
159    }
160
161    /// Get tree of all `Node`s in i3
162    pub fn get_tree(&mut self) -> io::Result<reply::Node> {
163        // self.send_msg(msg::Msg::Tree, "")?;
164        let buf = self.encode_msg(msg::Msg::Tree);
165        self.write_all(&buf[..])?;
166        Ok(self.receive_msg()?.body)
167    }
168
169    /// Get marks
170    pub fn get_marks(&mut self) -> io::Result<reply::Marks> {
171        // self.send_msg(msg::Msg::Marks, "")?;
172        let buf = self.encode_msg(msg::Msg::Marks);
173        self.write_all(&buf[..])?;
174        Ok(self.receive_msg()?.body)
175    }
176
177    /// Get your active bar ids
178    pub fn get_bar_ids(&mut self) -> io::Result<reply::BarIds> {
179        // self.send_msg(msg::Msg::BarConfig, "")?;
180        let buf = self.encode_msg(msg::Msg::BarConfig);
181        self.write_all(&buf[..])?;
182        Ok(self.receive_msg()?.body)
183    }
184
185    /// Get bar config by id (`get_bar_ids`)
186    pub fn get_bar_config<S: AsRef<str>>(&mut self, bar_id: S) -> io::Result<reply::BarConfig> {
187        self.send_msg(msg::Msg::BarConfig, bar_id)?;
188        Ok(self.receive_msg()?.body)
189    }
190
191    /// Get i3 version and config location
192    pub fn get_version(&mut self) -> io::Result<reply::Version> {
193        let buf = self.encode_msg(msg::Msg::Version);
194        self.write_all(&buf[..])?;
195        Ok(self.receive_msg()?.body)
196    }
197
198    /// Get i3 binding modes
199    pub fn get_binding_modes(&mut self) -> io::Result<reply::BindingModes> {
200        let buf = self.encode_msg(msg::Msg::BindingModes);
201        self.write_all(&buf[..])?;
202        Ok(self.receive_msg()?.body)
203    }
204
205    /// Get i3 config
206    pub fn get_config(&mut self) -> io::Result<reply::Config> {
207        let buf = self.encode_msg(msg::Msg::Config);
208        self.write_all(&buf[..])?;
209        Ok(self.receive_msg()?.body)
210    }
211
212    /// Convenience over `msg::Msg::Tick` and response
213    pub fn get_tick(&mut self) -> io::Result<reply::Success> {
214        let buf = self.encode_msg(msg::Msg::Tick);
215        self.write_all(&buf[..])?;
216        Ok(self.receive_msg()?.body)
217    }
218
219    /// Convenience over `msg::Msg::Sync` and response
220    pub fn get_sync(&mut self) -> io::Result<reply::Success> {
221        let buf = self.encode_msg(msg::Msg::Sync);
222        self.write_all(&buf[..])?;
223        Ok(self.receive_msg()?.body)
224    }
225
226    /// Get i3 binding state
227    pub fn get_binding_state(&mut self) -> io::Result<reply::BindingState> {
228        let buf = self.encode_msg(msg::Msg::BindingState);
229        self.write_all(&buf[..])?;
230        Ok(self.receive_msg()?.body)
231    }
232}
233
234impl Read for I3Stream {
235    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
236        self.0.read(buf)
237    }
238}
239
240impl Write for I3Stream {
241    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
242        self.0.write(buf)
243    }
244
245    fn flush(&mut self) -> io::Result<()> {
246        self.0.flush()
247    }
248}
249
250/// I3 event iterator, after you're subscribed to events (with the `subscribe`
251/// method). The iterator will advance each iteration on receiving an `Event`.
252/// These are decoded using `serde_json` and returned
253#[derive(Debug)]
254pub struct I3Iter<'a> {
255    stream: &'a mut I3Stream,
256}
257
258impl<'a> Iterator for I3Iter<'a> {
259    type Item = io::Result<event::Event>;
260
261    fn next(&mut self) -> Option<Self::Item> {
262        Some(self.stream.receive_event())
263    }
264}