# i3bar workspace buttons protocol

This document explains the protocol in which i3bar expects input for configuring workspace buttons. This feature is available since i3 version 4.23.

The program defined by the `workspace_command` configuration option for i3bar can modify the workspace buttons displayed by i3bar. The command should constantly print in its standard output a stream of messages following the protocol defined in this page.

If you are looking for the status line protocol instead, see https://i3wm.org/docs/i3bar-protocol.html.

## 1. The protocol

Each message should be a newline-delimited JSON array. The array is in the same format as the `GET_WORKSPACES` ipc event, see https://i3wm.org/docs/ipc.html#_workspaces_reply.

As an example, this is the output of the `i3-msg -t get_workspaces` command:

    [
      {
        "id": 94131549984064,
        "num": 1,
        "name": "1",
        "visible": false,
        "focused": false,
        "output": "HDMI-A-0",
        "urgent": false
      },
      {
        "id": 94131550477584,
        "num": 2,
        "name": "2",
        "visible": true,
        "focused": true,
        "output": "HDMI-A-0",
        "urgent": false
      },
      {
        "id": 94131550452704,
        "num": 3,
        "name": "3:some workspace",
        "visible": false,
        "focused": false,
        "output": "HDMI-A-0",
        "urgent": false
      }
    ]

Please note that this example was pretty printed for human consumption, with the `"rect"` field removed. Workspace button commands should output each array in one line.

Each element in the array represents a workspace. i3bar creates one workspace button for each element in the array. The order of these buttons is the same as the order of the elements in the array.

In general, we recommend subscribing to the `workspace` and `output` events, fetching the current workspace information with `GET_WORKSPACES`, modifying the JSON array in the response according to your needs and then printing it to the standard output. However, you are free to build a new message from the ground up.

### 1.1. Workspace objects in detail

The documentation of `GET_WORKSPACES` should be sufficient to understand the meaning of each property but here we provide extra notes for each property and its meaning with respect to i3bar.

All properties but `name` are optional.

id (integer)

  If it is included it will be used to switch to that workspace when you click the corresponding button. If it’s not provided, the `name` will be used. You can use the `id` field to present workspaces under a modified name.

num (integer)

  The only use of a workspace’s number is if the `strip_workspace_numbers` setting is enabled.

name (string)

  The only required property. If an `id` is provided you can freely change the `name` as you wish, effectively renaming the buttons of i3bar.

visible (boolean)

  Defaults to `false` if not included. `focused` takes precedence over it, however `visible` is important for more than one monitor.

focused (boolean)

  Defaults to `false` if not included. Generally, exactly one of the workspaces should be `focused`. If not, no button will have the `focused_workspace` color.

urgent (boolean)

  Defaults to `false` if not included.

rect (map)

  Not used by i3bar but will be ignored.

output (string)

  Defaults to the primary output if not included.

## 2. Examples

These example scripts require the jq utility to be installed but otherwise just use the standard `i3-msg` utility included with i3. However, you can write your own scripts in your preferred language, with the help of one of the pre-existing i3 libraries

### 2.1. Base configuration

    bar {
      …
      workspace_command /path/to/your/script.sh
      …
    }

### 2.2. Re-create the default behaviour of i3bar

Not very useful by itself but this will be the basic building block of all the following scripts. This one does not require `jq`.

    #!/bin/sh
    i3-msg -t subscribe -m '["workspace", "output"]' | {
        # Initially print the current workspaces before we receive any events. This
        # avoids having an empty bar when starting up.
        i3-msg -t get_workspaces;
        # Then, while we receive events, update the workspace information.
        while read EVENT; do i3-msg -t get_workspaces; done;
    }

### 2.3. Hide workspace named `foo` unless if it is focused.

    #!/bin/sh
    i3-msg -t subscribe -m '["workspace", "output"]' | {
        i3-msg -t get_workspaces;
        while read EVENT; do i3-msg -t get_workspaces; done;
    } | jq --unbuffered -c '[ .[] | select(.name != "foo" or .focused) ]'

Important! Make sure you use the `--unbuffered` flag with `jq`, otherwise you might not get the changes in real-time but whenever they are flushed, which might mean that you are getting an empty bar until enough events are written.

### 2.4. Show empty workspaces `foo` and `bar` on LVDS1 even if they do not exist at the moment.

    #!/bin/sh
    i3-msg -t subscribe -m '["workspace", "output"]' | {
        i3-msg -t get_workspaces;
        while read EVENT; do i3-msg -t get_workspaces; done;
    } | jq --unbuffered -c '
        def fake_ws(name): {
            name: name,
            output: "LVDS1",
        };
        . + [ fake_ws("foo"), fake_ws("bar") ] | unique_by(.name)
    '

### 2.5. Sort workspaces in reverse alphanumeric order

    #!/bin/sh
    i3-msg -t subscribe -m '["workspace", "output"]' | {
        i3-msg -t get_workspaces;
        while read EVENT; do i3-msg -t get_workspaces; done;
    } | jq --unbuffered -c 'sort_by(.name) | reverse'

### 2.6. Append "foo" to the name of each workspace

    #!/bin/sh
    i3-msg -t subscribe -m '["workspace", "output"]' | {
        i3-msg -t get_workspaces;
        while read EVENT; do i3-msg -t get_workspaces; done;
    } | jq --unbuffered -c '[ .[] | .name |= . + " foo" ]'