Crate tokio_i3ipc

source ·
Expand description

tokio-i3ipc

This crate provides types and functions for working with i3’s IPC protocol in an async context and with tokio. It re-exports the subcrate i3ipc-types because it is also used for a synchronous implementation of the protocol.

This library follows a similar API to the synchronous version. All important functions live on the I3 type. You must first await a connect call, then you can execute commands, send/read messages from i3, or subscribe to listen to Events.

Subscribe & Listen

use tokio_i3ipc::{event::{Event,Subscribe}, I3};

#[tokio::main(flavor = "current_thread")]
async fn main() -> io::Result<()> {
    let mut i3 = I3::connect().await?;
    i3.subscribe([Subscribe::Window]).await?;

    let mut listener = i3.listen();
    while let Some(event) = listener.next().await {
        match event? {
            Event::Workspace(ev) => println!("workspace change event {:?}", ev),
            Event::Window(ev) => println!("window event {:?}", ev),
            Event::Output(ev) => println!("output event {:?}", ev),
            Event::Mode(ev) => println!("mode event {:?}", ev),
            Event::BarConfig(ev) => println!("bar config update {:?}", ev),
            Event::Binding(ev) => println!("binding event {:?}", ev),
            Event::Shutdown(ev) => println!("shutdown event {:?}", ev),
            Event::Tick(ev) => println!("tick event {:?}", ev),
        }
    }
    Ok(())
}

Sending/Reading from I3

To send messages to i3, call any of the get_* functions on I3.

use std::io;

use tokio_i3ipc::{reply, I3};

#[tokio::main(flavor = "current_thread")]
async fn main() -> io::Result<()> {
    let mut i3 = I3::connect().await?;
    // this type can be inferred, here is written explicitly:
    let worksp: reply::Workspaces = i3.get_workspaces().await?;
    println!("{:#?}", worksp);

    Ok(())
}

All the get_* functions on I3 are simple wrappers around two main async functions. You could write any of them yourself, in fact:

use tokio_i3ipc::{msg, reply, MsgResponse, I3};

#[tokio::main(flavor = "current_thread")]
let mut i3 = I3::connect().await?;
// send msg RunCommand with a payload
let payload = "some_command";
i3.send_msg_body(msg::Msg::RunCommand, payload).await?;
let resp: MsgResponse<Vec<reply::Success>> = i3.read_msg().await?;

Modules

Implements tokio_codec’s Decoder trait
For subscribing and receiving events, each struct matches a particular Subscribe variant. For instance, subscribing with Subscribe::Workspace will net Event::Workspace when workspace events are sent over the ipc.
For sending messages to i3
Contains structs for deserializing messages from i3

Structs

Newtype wrapper for UnixStream that implements i3’s IPC
Instead of returning an enum, we’re returning a struct containing the Msg type and some body. An advantage to this over the enum method is that there is no minimum memory size that we must have. This is helpful when some variants are very large compared to others, as in the case of say reply::Node vs reply::Config

Constants

Traits

Types implementing this are provided a connect function and return a stream
Trait containing methods to encode and decode message from i3

Functions

Given an event type and payload this function will deserialize the proper struct
Decode a response into an Event
Decode a response into a MsgResponse
Convenience function that decodes a single response and passes the type and undecoded buffer to a closure
get socket path from i3