sway-ipc(7)

🌸 hey bestie, welcome to sway-ipc(7) 🌸

okay so this is the manual page for sway-ipc β€” the IPC protocol for sway(1) πŸ’… it's literally the group chat between your programs and your sway process. slay.

✨ NAME ✨

sway-ipc β€” IPC protocol for sway

πŸ’– DESCRIPTION πŸ’–

This details the interprocess communication (IPC) protocol for sway(1). This IPC protocol can be used to control or obtain information from a sway process. no cap.

The IPC protocol uses a UNIX socket as the method of communication. The path to the socket is stored in the environment variable SWAYSOCK and, for backwards compatibility with i3, I3SOCK. You can also retrieve the socket path by calling sway --get-socketpath. iykyk 🫢


πŸŽ€ MESSAGE AND REPLY FORMAT πŸŽ€

The format for messages and replies is:

<magic-string> <payload-length> <payload-type> <payload>

Where:

  • <magic-string> is i3-ipc, for compatibility with i3
  • <payload-length> is a 32-bit integer in native byte order
  • <payload-type> is a 32-bit integer in native byte order

For example, sending the exit command would look like the following hexdump:

00000000 | 69 33 2d 69 70 63 04 00 00 00 00 00 00 00 65 78 |i3-ipc........ex|
00000010 | 69 74                                           |it              |

The payload for replies will be a valid serialized JSON data structure. periodt ✨


🌈 MESSAGES AND REPLIES 🌈

The following message types and their corresponding reply types are currently supported. For all replies, any properties not listed are subject to removal. bestie, don't get attached to undocumented properties 😭

  • 0 β€” RUN_COMMAND β€” Runs the payload as sway commands
  • 1 β€” GET_WORKSPACES β€” Get the list of current workspaces
  • 2 β€” SUBSCRIBE β€” Subscribe the IPC connection to the events listed in the payload
  • 3 β€” GET_OUTPUTS β€” Get the list of current outputs
  • 4 β€” GET_TREE β€” Get the node layout tree
  • 5 β€” GET_MARKS β€” Get the names of all the marks currently set
  • 6 β€” GET_BAR_CONFIG β€” Get the specified bar config or a list of bar config names
  • 7 β€” GET_VERSION β€” Get the version of sway that owns the IPC socket
  • 8 β€” GET_BINDING_MODES β€” Get the list of binding mode names
  • 9 β€” GET_CONFIG β€” Returns the config that was last loaded
  • 10 β€” SEND_TICK β€” Sends a tick event with the specified payload
  • 11 β€” SYNC β€” Replies failure object for i3 compatibility
  • 12 β€” GET_BINDING_STATE β€” Request the current binding state, e.g. the currently active binding mode name.
  • 100 β€” GET_INPUTS β€” Get the list of input devices
  • 101 β€” GET_SEATS β€” Get the list of seats

πŸ’… 0. RUN_COMMAND πŸ’…

MESSAGE

Parses and runs the payload as sway commands. main character energy fr fr πŸ”₯

REPLY

An array of objects corresponding to each command that was parsed. Each object has the property success, which is a boolean indicating whether the command was successful. The object may also contain the properties error and parse_error. The error property is a human readable error message while parse_error is a boolean indicating whether the reason the command failed was because the command was unknown or not able to be parsed. okay so parse_error is the "wait, what command??" flag πŸ’€

Example Reply:

[
     {
          "success": true
     },
     {
          "success": false,
          "parse_error": true,
          "error": "Invalid/unknown command"
     }
]

πŸ¦‹ 1. GET_WORKSPACES πŸ¦‹

MESSAGE

Retrieves the list of workspaces.

REPLY

The reply is an array of objects corresponding to each workspace. Each object has the following properties:

  • num β€” integer β€” The workspace number or -1 for workspaces that do not start with a number
  • name β€” string β€” The name of the workspace
  • visible β€” boolean β€” Whether the workspace is currently visible on any output
  • focused β€” boolean β€” Whether the workspace is currently focused by the default seat (seat0)
  • urgent β€” boolean β€” Whether a window on the workspace has the urgent flag set
  • rect β€” object β€” The bounds of the workspace. It consists of x, y, width, and height
  • output β€” string β€” The name of the output that the workspace is on

that's the whole vibe check for workspaces, bestie πŸ’–

And here's what that reply actually looks like when it comes back at you πŸ’…

[
     {
          "num": 1,
          "name": "1",
          "visible": true,
          "focused": true,
          "rect": {
               "x": 0,
               "y": 23,
               "width": 1920,
               "height": 1057
          },
          "output": "eDP-1"
     },
]

πŸ¦‹ 2. SUBSCRIBE πŸ¦‹

MESSAGE

Okay so this one is literally you telling the IPC connection "bestie, keep me in the loop." You subscribe this IPC connection to the event types you list in the message payload. The payload should be a valid JSON array of events β€” yes, an array, don't try to be cute and send one string. Scroll down to the EVENTS section for the full list of what you can subscribe to, iykyk.

REPLY

You get back a single object containing the property success, which is a boolean telling you whether the subscription went through or not. That's it. That's the whole reply. Iconic and minimal πŸŽ€

Example Reply:

{
     "success": true
}

✨ 3. GET_OUTPUTS ✨

MESSAGE

Retrieve the list of outputs. That's your monitors, your displays, your whole "where am I even rendering to" situation πŸ–₯️

REPLY

An array of objects, one per output. Each object is stacked with the following properties:

  • name (string) β€” The name of the output. On DRM, this is the connector.
  • make (string) β€” The make of the output.
  • model (string) β€” The model of the output.
  • serial (string) β€” The output's serial number as a hexadecimal string.
  • active (boolean) β€” Whether this output is active/enabled.
  • dpms (boolean) β€” (Deprecated, use power instead) Whether this output is on/off (via DPMS).
  • power (boolean) β€” Whether this output is on/off.
  • primary (boolean) β€” For i3 compatibility, this will be false. It does not make sense in Wayland. Like, fr, there's no "primary" monitor vibe here.
  • scale (float) β€” The scale currently in use on the output or -1 for disabled outputs.
  • subpixel_hinting (string) β€” The subpixel hinting current in use on the output. This can be rgb, bgr, vrgb, vbgr, or none.
  • transform (string) β€” The transform currently in use for the output. This can be normal, 90, 180, 270, flipped-90, flipped-180, or flipped-270.
  • current_workspace (string) β€” The workspace currently visible on the output or null for disabled outputs.
  • modes (array) β€” An array of supported mode objects. Each object contains width, height, and refresh.
  • current_mode (object) β€” An object representing the current mode containing width, height, and refresh.
  • rect (object) β€” The bounds for the output consisting of x, y, width, and height.
  • hdr (boolean) β€” Whether HDR is enabled.
Heads up bestie: dpms is deprecated, so if you're writing new stuff, use power instead. The old one still shows up for compatibility but it's giving legacy energy πŸ’€

Example Reply:

[
     {
          "name": "HDMI-A-2",
          "make": "Unknown",
          "model": "NS-19E310A13",
          "serial": "0x00000001",
          "active": true,
          "primary": false,
          "scale": 1.0,
          "subpixel_hinting": "rgb",
          "transform": "normal",
          "current_workspace": "1",
          "modes": [
               {
                    "width": 640,
                    "height": 480,
                    "refresh": 59940
               },
               {
                    "width": 800,
                    "height": 600,
                    "refresh": 60317
               },
               {
                    "width": 1024,
                    "height": 768,
                    "refresh": 60004
               },
               {
                    "width": 1920,
                    "height": 1080,
                    "refresh": 60000
               }
          ],
          "current_mode": {
               "width": 1920,
               "height": 1080,
               "refresh": 60000
          }
     }
]

🌸 4. GET_TREE 🌸

MESSAGE

Retrieve a JSON representation of the tree. Yes, the whole layout tree β€” containers, windows, the entire nesting situation. Main character energy for real πŸ‘‘

REPLY

An array of objects that represent the current tree. Each object represents one node and will have the following properties:

(and we're about to get into those properties next β€” don't go anywhere πŸ’–)

  • id β€” integer β€” the internal unique ID for this node. yes it's a number, no you can't pick it πŸ’…
  • name β€” string β€” the name of the node, like the output name or the window title. for the scratchpad this will be __i3_scratch, purely for compatibility with i3 🫢
  • type β€” string β€” the node type, and it's one of: root, output, workspace, con, or floating_con
  • border β€” string β€” the border style for the node: normal, none, pixel, or csd
  • current_border_width β€” integer β€” how many pixels are being used for the border width
  • layout β€” string β€” the node's layout, which can be splith, splitv, stacked, tabbed, or output
  • orientation β€” string β€” the node's orientation: vertical, horizontal, or none
  • percent β€” float β€” the percentage of the node's parent that it takes up, or null for the root and other special nodes such as the scratchpad 🌸
  • rect β€” object β€” the absolute geometry of the node. window decorations are excluded from this, but borders are included ✨
  • window_rect β€” object β€” the geometry of the content inside the node, and these coordinates are relative to the node itself. window decorations and borders live outside the window_rect πŸŽ€
  • deco_rect β€” object β€” the geometry of the decorations for the node, relative to the parent node
  • geometry β€” object β€” the natural geometry of the contents if it were to size itself πŸ‘‘
  • urgent β€” boolean β€” whether the node or any of its descendants has the urgent hint set. > ngl bestie, note that this one may not exist when compiled without xwayland support πŸ’€
  • sticky β€” boolean β€” whether the node is sticky (shows on all workspaces) πŸ¦‹
  • marks β€” array β€” the list of marks assigned to the node
  • focused β€” boolean β€” whether the node is currently focused by the default seat (seat0)
  • focus β€” array β€” array of child node IDs in the current focus order
  • nodes β€” array β€” the tiling children nodes for the node 🌈
  • floating_nodes β€” array β€” the floating children nodes for the node
  • representation β€” string β€” (only workspaces!) a string representation of the layout of the workspace that can be used as an aid in

...okay so that last row's description wrapped into "submitting reproduction steps for bug reports" β€” that's still the field from before, nothing new, carry on πŸ’…

  • fullscreen_mode β€” integer β€” (only containers and windows πŸͺŸ) the fullscreen mode of the node. 0 means none, 1 means full workspace, and 2 means global fullscreen.
  • floating β€” string β€” the floating state of the container. Can be either "auto_off" or "user_on" ✨
  • scratchpad_state β€” string β€” whether the window is in the scratchpad. Can be either "none" or "fresh" πŸ“
  • app_id β€” string β€” (only windows) for an xdg-shell window, the name of the application, if set. Otherwise null 🫢
  • pid β€” integer β€” (only windows) the PID of the application that owns the window πŸ”₯
  • foreign_toplevel_identifier β€” string β€” (only windows) the ext-foreign-toplevel-list-v1 toplevel identifier of this node πŸŽ€
  • visible β€” boolean β€” (only windows) whether the node is visible πŸ‘€
  • shell β€” string β€” (only windows) the shell of the window, such as xdg_shell or xwayland 🐚
  • inhibit_idle β€” boolean β€” (only windows) whether the window is inhibiting the idle state 😴
  • idle_inhibitors β€” object β€” (only windows) an object containing the state of the application and user idle inhibitors. application can be enabled or none. user can be focus, fullscreen, open, visible or none.
  • sandbox_engine β€” string β€” (only windows) the associated sandbox engine (or null) 🧚
  • sandbox_app_id β€” string β€” (only windows) the app ID provided by the associated sandbox engine (or null)
  • sandbox_instance_id β€” string β€” (only windows) the instance ID provided by the associated sandbox engine (or null)
  • tag β€” string β€” (only windows) for an xdg-shell window, tag of the toplevel, if set. Otherwise null 🏷️
  • window β€” integer β€” (only xwayland windows) the X11 window ID for the xwayland window πŸ’€
  • window_properties β€” object β€” (only xwayland windows) an object containing the title, class, instance, window_role, window_type, and transient_for for the window 🌈
ngl bestie, that's a lot of fields β€” but like, every single one is just a little fact about a node, no cap. Missing ones just come back as null, which is the node equivalent of "no thoughts, head empty" πŸ™ˆ

Example Reply (the GET_TREE one β€” buckle up bestie, it's a whole saga) 🌳

Okay so this is what a real reply to GET_TREE looks like. It's a recursive thing β€” containers inside containers inside containers, all the way down, like a set of matryoshka dolls that went to therapy. Notice the top node is "type": "root", then under it comes an "output" called __i3, then a "workspace" called __i3_scratch, and then your actual outputs start showing up. Everything under nodes is a child; everything under floating_nodes is a floater. Slay.

{
     "id": 1,
     "name": "root",
     "rect": {
          "x": 0,
          "y": 0,
          "width": 1920,
          "height": 1080
     },
     "focused": false,
     "focus": [
          3
     ],
     "border": "none",
     "current_border_width": 0,
     "layout": "splith",
     "orientation": "horizontal",
     "percent": null,
     "window_rect": {
          "x": 0,
          "y": 0,
          "width": 0,
          "height": 0
     },
     "deco_rect": {
          "x": 0,
          "y": 0,
          "width": 0,
          "height": 0
     },
     "geometry": {
          "x": 0,
          "y": 0,
          "width": 0,
          "height": 0
     },
     "window": null,
     "urgent": false,
     "floating_nodes": [
     ],
     "sticky": false,
     "type": "root",
     "nodes": [
          {
               "id": 2147483647,
               "name": "__i3",
               "rect": {
                    "x": 0,
                    "y": 0,
                    "width": 1920,
                    "height": 1080
               },
               "focused": false,
               "focus": [
                    2147483646
               ],
               "border": "none",
               "current_border_width": 0,
               "layout": "output",
               "orientation": "horizontal",
               "percent": null,
               "window_rect": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "deco_rect": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "geometry": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "window": null,
               "urgent": false,
               "floating_nodes": [
               ],
               "sticky": false,
               "type": "output",
               "nodes": [
                    {
                         "id": 2147483646,
                         "name": "__i3_scratch",
                         "rect": {
                              "x": 0,
                              "y": 0,
                              "width": 1920,
                              "height": 1080
                         },
                         "focused": false,
                         "focus": [
                         ],
                         "border": "none",
                         "current_border_width": 0,
                         "layout": "splith",
                         "orientation": "horizontal",
                         "percent": null,
                         "window_rect": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "deco_rect": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "geometry": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "window": null,
                         "urgent": false,
                         "floating_nodes": [
                         ],
                         "sticky": false,
                         "type": "workspace"
                    }
               ]
          },
          {
               "id": 3,
               "name": "eDP-1",
               "rect": {
                    "x": 0,
                    "y": 0,
                    "width": 1920,
                    "height": 1080
               },
               "focused": false,
               "focus": [
                    4
               ],
               "border": "none",
               "current_border_width": 0,
               "layout": "output",
               "orientation": "none",
               "percent": 1.0,
               "window_rect": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "deco_rect": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "geometry": {
                    "x": 0,
                    "y": 0,
                    "width": 0,
                    "height": 0
               },
               "window": null,
               "urgent": false,
               "floating_nodes": [
               ],
               "sticky": false,
               "type": "output",
               "active": true,
               "primary": false,
               "make": "Unknown",
               "model": "0x38ED",
               "serial": "0x00000000",
               "scale": 1.0,
               "transform": "normal",
               "current_workspace": "1",
               "modes": [
                    {
                         "width": 1920,
                         "height": 1080,
                         "refresh": 60052
                    }
               ],
               "current_mode": {
                    "width": 1920,
                    "height": 1080,
                    "refresh": 60052
               },
               "nodes": [
                    {
                         "id": 4,
                         "name": "1",
                         "rect": {
                              "x": 0,
                              "y": 23,
                              "width": 1920,
                              "height": 1057
                         },
                         "focused": false,
                         "focus": [
                              6,
                              5
                         ],
                         "border": "none",
                         "current_border_width": 0,
                         "layout": "splith",
                         "orientation": "horizontal",
                         "percent": null,
                         "window_rect": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "deco_rect": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "geometry": {
                              "x": 0,
                              "y": 0,
                              "width": 0,
                              "height": 0
                         },
                         "window": null,
                         "urgent": false,
                         "floating_nodes": [
                         ],
                         "sticky": false,
                         "num": 1,
                         "output": "eDP-1",
                         "type": "workspace",
                         "representation": "H[URxvt termite]",
                         "nodes": [
                              {
                                   "id": 5,
                                   "name": "urxvt",
                                   "rect": {
                                        "x": 0,
                                        "y": 23,
                                        "width": 960,
                                        "height": 1057
                                   },
                                   "focused": false,
                                   "focus": [
                                   ],
                                   "border": "normal",
                                   "current_border_width": 2,
                                   "layout": "none",
                                   "orientation": "none",
                                   "percent": 0.5,
                                   "window_rect": {
                                        "x": 2,
                                        "y": 0,
                                        "width": 956,
                                        "height": 1030
                                   },
                                   "deco_rect": {
                                        "x": 0,
                                        "y": 0,
                                        "width": 960,
                                        "height": 25
                                   },
                                   "geometry": {
                                        "x": 0,

And yes, it keeps going from there β€” the tree does not care about your scrollbar, bestie 😭 (more in the next part, don't touch that dial) 🫢

                                                   "y": 0,
                                                   "width": 1124,
                                                   "height": 422
                                              },
                                              "window": 4194313,
                                              "urgent": false,
                                              "floating_nodes": [
                                              ],
                                              "sticky": false,
                                              "type": "con",
                                              "fullscreen_mode": 0,
                                              "pid": 23959,
                                              "app_id": null,
                                              "visible": true,
                                              "shell": "xwayland",
                                              "inhibit_idle": true,
                                              "idle_inhibitors": {
                                                   "application": "none",
                                                   "user": "visible",
                                              },
                                              "window_properties": {
                                                   "class": "URxvt",
                                                   "instance": "urxvt",
                                                   "title": "urxvt",
                                                   "transient_for": null
                                              },
                                              "nodes": [
                                              ]
                                         },
                                         {
                                              "id": 6,
                                              "name": "",
                                              "rect": {
                                                   "x": 960,
                                                   "y": 23,
                                                   "width": 960,
                                                   "height": 1057
                                              },
                                              "focused": true,
                                              "focus": [
                                              ],
                                              "border": "normal",
                                              "current_border_width": 2,
                                              "layout": "none",
                                              "orientation": "none",
                                              "percent": 0.5,
                                              "window_rect": {
                                                   "x": 2,
                                                   "y": 0,
                                                   "width": 956,
                                                   "height": 1030
                                              },
                                              "deco_rect": {
                                                   "x": 0,
                                                   "y": 0,
                                                   "width": 960,
                                                   "height": 25
                                              },
                                              "geometry": {
                                                   "x": 0,
                                                   "y": 0,
                                                   "width": 817,
                                                   "height": 458
                                              },
                                              "window": null,
                                              "urgent": false,
                                              "floating_nodes": [
                                              ],
                                              "sticky": false,
                                              "type": "con",
                                              "fullscreen_mode": 0,
                                              "pid": 25370,
                                              "app_id": "termite",
                                              "visible": true,
                                              "shell": "xdg_shell",
                                              "inhibit_idle": false,
                                              "idle_inhibitors": {
                                                   "application": "none",
                                                   "user": "fullscreen",
                                              },
                                              "nodes": [
                                              ]
                                         }
                                    ]
                               }
                          ]
                     }
                ]
           }

Ok that's the rest of the tree dump bestie, we survived πŸ˜­πŸ’– the JSON was long but we ate.


5. GET_MARKS πŸŽ€

MESSAGE

Get the marks that are currently set, bestie. Like, right now, as they are.

REPLY

An array of the marks currently set. And here's the little detail that matters: since each mark can only be set for one container, this is a set, so every value is unique and the order is undefined. So don't come for me about ordering, it's giving "no promises" πŸ’…

Example Reply:

[
     "one",
     "test"
]

6. GET_BAR_CONFIG (WITHOUT A PAYLOAD) πŸ¦‹

MESSAGE

When you send this one without a payload, it retrieves the list of configured bar IDs. Simple as that, no cap.

REPLY

An array of bar IDs, which are strings. That's it. That's the whole vibe ✨

Example Reply:

[
     "bar-0",
     "bar-1"
]

6. GET_BAR_CONFIG (WITH A PAYLOAD) 🌈

MESSAGE

But when you do send it with a bar ID as the payload, it retrieves the config associated with the bar ID you specified in the payload. This is what swaybar uses, but for real it could also be used for third-party bars β€” highkey a whole serve πŸ”₯

REPLY

An object that represents the configuration for the bar with the bar ID you sent as the payload. The following properties exist, with more information about their values in sway-bar(5):


Okay so this next bit is the whole vibe of a bar config β€” every property it can have, what type of data each one is, and what it's actually doing. Read it like a menu, bestie, because that's basically what it is πŸ’…

  • id (string) β€” the bar ID. That's it, that's the whole thing, it's just the name of the bar.
  • mode (string) β€” the mode for the bar. It can be dock, hide, or invisible.
  • position (string) β€” the bar's position. Right now it can be either bottom or top.
  • status_command (string) β€” the command that gets run to generate the status line. yes, that whole command string, right there in the config ✨
  • font (string) β€” the font used for the text on the bar.
  • workspace_buttons (boolean) β€” whether to display the workspace buttons on the bar or not.
  • workspace_min_width (integer) β€” the minimum width, in px, for those workspace buttons on the bar.
  • binding_mode_indicator (boolean) β€” whether to display the current binding mode on the bar.
  • verbose (boolean) β€” for i3 compatibility this will be the boolean value false. lowkey iconic of it tbh.
  • colors (object) β€” an object holding the #RRGGBBAA colors to use for the bar. There's more info on this below, keep scrolling 🫢
  • gaps (object) β€” an object representing the gaps for the bar, made up of top, right, bottom, and left. all four, no skimping.
  • bar_height (integer) β€” the absolute height to use for the bar, or 0 to automatically size it based on the font. 0 means "figure it out yourself", basically.
  • status_padding (integer) β€” the vertical padding to use for the status line.
  • status_edge_padding (integer) β€” the horizontal padding to use for the status line when it's at the end of an output.

That's the full rundown, no cap β€” every property, every type, nothing skipped πŸ’–

The colors object has these properties, and literally every single one of them is a string holding the #RRGGBBAA representation of the color πŸ’… no cap:

  • background β€” the color for the bar background on outputs that are not focused
  • statusline β€” the color for the status line text on outputs that are not focused
  • separator β€” the color for the separator text on outputs that are not focused
  • focused_background β€” the color for the background of the bar on the focused output πŸ‘‘
  • focused_statusline β€” the color for the status line text on the focused output
  • focused_separator β€” the color for the separator text on the focused output
  • focused_workspace_text β€” the color for the text of the focused workspace button
  • focused_workspace_bg β€” the color for the background of the focused workspace button
  • focused_workspace_border β€” the color for the border of the focused workspace button
  • active_workspace_text β€” the color for the text of the workspace buttons for the visible workspaces on outputs that are not focused
  • active_workspace_bg β€” the color for the background of the workspace buttons for the visible workspaces on outputs that are not focused
  • active_workspace_border β€” the color for the border of the workspace buttons for the visible workspaces on outputs that are not focused
  • inactive_workspace_text β€” the color for the text of the workspace buttons for workspaces that are not visible πŸ™ˆ
  • inactive_workspace_bg β€” the color for the background of the workspace buttons for workspaces that are not visible
  • inactive_workspace_border β€” the color for the border of the workspace buttons for workspaces that are not visible
  • urgent_workspace_text β€” the color for the text of the workspace buttons for workspaces that contain an urgent window πŸ”₯
  • urgent_workspace_bg β€” the color for the background of the workspace buttons for workspaces that contain an urgent window
  • urgent_workspace_border β€” the color for the border of the workspace buttons for workspaces that contain an urgent window
  • binding_mode_text β€” the color for the text of the binding mode indicator
  • binding_mode_bg β€” the color for the background of the binding mode indicator
  • binding_mode_border β€” the color for the border of the binding mode indicator
bestie pls note 🫢 the whole object is just color strings β€” twenty-one of them β€” so if you're diffing your config against the reply, every key here should look like #RRGGBBAA or something is off.

Example Reply πŸ’…

{
     "id": "bar-0",
     "mode": "dock",
     "position": "top",
     "status_command": "while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done",
     "font": "monospace 10",
     "gaps": {
          "top": 0,
          "right": 0,
          "bottom": 0,
          "left": 0
     },
     "bar_height": 0,
     "status_padding": 1,
     "status_edge_padding": 3,
     "workspace_buttons": true,
     "workspace_min_width": 0,
     "binding_mode_indicator": true,
     "verbose": false,
     "pango_markup": false,
     "colors": {
          "background": "#323232ff",
          "statusline": "#ffffffff",
          "separator": "#666666ff",
          "focused_background": "#323232ff",
          "focused_statusline": "#ffffffff",
          "focused_separator": "#666666ff",
          "focused_workspace_border": "#4c7899ff",
          "focused_workspace_bg": "#285577ff",
          "focused_workspace_text": "#ffffffff",
          "inactive_workspace_border": "#32323200",
          "inactive_workspace_bg": "#32323200",
          "inactive_workspace_text": "#5c5c5cff",
          "active_workspace_border": "#333333ff",
          "active_workspace_bg": "#5f676aff",
          "active_workspace_text": "#ffffffff",
          "urgent_workspace_border": "#2f343aff",
          "urgent_workspace_bg": "#900000ff",
          "urgent_workspace_text": "#ffffffff",
          "binding_mode_border": "#2f343aff",
          "binding_mode_bg": "#900000ff",
          "binding_mode_text": "#ffffffff"
     },
}

okay that's a whole lot of JSON but look at it. it's giving organization. it's giving aesthetic. πŸŽ€


7. GET_VERSION</p> ⭐

MESSAGE

bestie. it literally just asks the sway process for its version info. that's it. that's the message.

REPLY

an object with all these properties in it:

  • major (integer) β€” the major version of the sway process
  • minor (integer) β€” the minor version of the sway process
  • patch (integer) β€” the patch version of the sway process
  • human_readable (string) β€” a human readable version string that will likely contain more useful information such as the git commit short hash and git branch
  • loaded_config_file_name (string) β€” the path to the loaded config file

Example Reply 🌸

{
     "human_readable": "1.0-rc1-117-g2f7247e0 (Feb 24 2019, branch 'master')",
     "major": 1,
     "minor": 0,
     "patch": 0,
     "loaded_config_file_name": "/home/redsoxfan/.config/sway/config"
}

8. GET_BINDING_MODES</p> πŸ¦‹

MESSAGE

asks for the list of binding modes that are currently configured. very demure. very mindful.

REPLY

an array of strings, where each string is the name of a binding mode. and no matter what, this will always contain at least one mode (currently default), which is the default binding mode β€” so you're never gonna get an empty list back, okurrr 🫢

Example Reply ✨

[
     "default",
     "resize",
]

9. GET_CONFIG</p> πŸ“

MESSAGE

hands you back the contents of the config that was last loaded, like a little mixtape but make it dotfiles.

REPLY

an object with a single string property holding the contents of the config πŸ’–

Example Reply 🌈

{
     "config": "set $mod Mod4\nbindsym $mod+q exit\n"
}

10. SEND_TICK</p> πŸ”₯

MESSAGE

this is the sync-up moment. it issues a TICK event to all clients subscribing to the event, to make sure that all events prior to the tick were received. and if you give it a payload, that payload gets included in the TICK event. cute, right? it's giving "did everyone see that, sound off in the chat". πŸ’…

REPLY

a single object containing the property success, which is a boolean value indicating whether the TICK event was sent.

Example Reply ⭐

{
     "success": true
}

11. SYNC</p> πŸ’€

MESSAGE

okay so this one's here for i3 compatibility, and that's the whole vibe β€” it just returns a failure object, because it does not make sense to implement in sway due to the X11 nature of the command. if you are curious about what this IPC command does in i3, refer to the i3 documentation. not us, bestie. go ask i3. πŸ™ˆ

REPLY

a single object that contains the property success, which is set to the boolean value false.

ngl the word "Exact" is doing a lot of heavy lifting here β€” this reply is not a maybe, it's not a depends. it's just false. periodt.

Exact Reply πŸŽ€

{
     "success": false
}

12. GET_BINDING_STATE</p> πŸ‘‘

MESSAGE

returns the currently active binding mode. the main character mode, if you will.

REPLY

a single object that contains the property name, which is set to the currently active binding mode as a string.

Example Reply πŸ’œ

{
     "name": "default"
}

100. GET_INPUTS</p> 🧚

MESSAGE

retrieves a list of the input devices currently available. yes, all of them. your keyboard, your mouse, whatever cursed peripheral you've got plugged in β€” it's all on the list. πŸ’–

REPLY

an array of objects corresponding to each input device. each object has the following properties:

  • identifier β€” string πŸ†” β€” the identifier for the input device, bestie
  • name β€” string 🏷️ β€” the human readable name for the device
  • vendor β€” integer 🏭 β€” the vendor code for the input device
  • product β€” integer πŸ“¦ β€” the product code for the input device
  • type β€” string πŸŽ€ β€” the device type. rn this can be keyboard, pointer, touch, tablet_tool, tablet_pad, or switch
  • xkb_active_layout_name β€” string ⌨️ β€” (only keyboards!) the name of the active keyboard layout
  • xkb_layout_names β€” array πŸ“‹ β€” (only keyboards!) a list a layout names configured for the keyboard
  • xkb_active_layout_index β€” integer πŸ”’ β€” (only keyboards!) the index of the active keyboard layout
  • scroll_factor β€” floating πŸ–±οΈ β€” (only pointers!) multiplier applied on scroll event values
  • libinput β€” object 🧚 β€” (only libinput devices!) an object describing the current device settings. see below for more info πŸ‘‡

so yeah β€” the libinput object describes the device configuration for libinput devices ✨ and here's the thing: only properties that are supported for the device will be added to the object. no extra filler, she's selective πŸ’…

and bestie, in addition to the possible options listed, all string properties may also be unknown, in the case that a new option is added to libinput 🫢 (yes that's a real vibe β€” libinput moves fast, sway keeps up, and unknown is the diplomatic answer 😌)

for the meaning of the possible values, go read sway-input(5) πŸ“– β€” it's all spelled out there.

the following properties will be included for devices that support them: 🌸

Okay so this next chunk is the libinput device properties vibe check β€” it's a whole list of properties a device can have, each with its data type and what it means. Think of it as the device's little personality profile πŸ’…

  • send_events (string) β€” whether the device is actually sending events. It can be enabled, disabled, or disabled_on_external_mouse.
  • tap (string) β€” whether tap to click is on. It can be enabled or disabled.
  • tap_button_map (string) β€” the finger-to-button mapping that's in use for tapping. It can be lmr or lrm.
  • tap_drag (string) β€” whether tap-and-drag is on. It can be enabled or disabled.
  • tap_drag_lock (string) β€” whether drag-lock is on. It can be enabled, disabled, or enabled_sticky.
  • accel_speed (double) β€” the pointer-acceleration currently in use.
  • accel_profile (string) β€” the acceleration profile in use. It can be none, flat, or adaptive.
  • natural_scroll (string) β€” whether natural scrolling is on. It can be enabled or disabled.
  • left_handed (string) β€” whether left-handed mode is on. It can be enabled or disabled.
  • click_method (string) β€” the click method in use. It can be none, button_areas, or clickfinger.
  • click_button_map (string) β€” the finger-to-button mapping in use for clickfinger. It can be lmr or lrm.
  • middle_emulation (string) β€” whether middle emulation is on. It can be enabled or disabled.
  • scroll_method (string) β€” the scroll method in use. It can be none, two_finger, edge, or on_button_down.
  • scroll_button (int) β€” the scroll button to use when scroll_method is on_button_down. This one's given as an input event code, jsyk.
  • scroll_button_lock (string) β€” whether scroll button lock is on. It can be enabled or disabled.
  • dwt (string) β€” whether disable-while-typing is on. It can be enabled or disabled.
  • dwtp (string) β€” whether disable-while-trackpointing is on. It can be enabled or_disabled_ πŸ’€ (no bestie I didn't typo that, that's literally what the page says, love that for us)
  • calibration_matrix (array) β€” an array of 6 floats representing the calibration matrix for absolute devices such as touchscreens.
Real talk 🫢 β€” those string values are exactly what you'll see and send. Don't go inventing your own spellings of two_finger or enabled_sticky, the parser will simply not be your friend.

Example Reply:

     [
          {
               "identifier": "1:1:AT_Translated_Set_2_keyboard",
               "name": "AT Translated Set 2 keyboard",
               "vendor": 1,
               "product": 1,
               "type": "keyboard",
               "xkb_active_layout_name": "English (US)",
               "libinput": {
                    "send_events": "enabled"
               }
          },
          {
               "identifier": "1267:5:Elan_Touchpad",
               "name": "Elan Touchpad",
               "vendor": 1267,
               "product": 5,
               "type": "pointer",
               "libinput": {
                    "send_events": "enabled",
                    "tap": "enabled",
                    "tap_button_map": "lmr",
                    "tap_drag": "enabled",
                    "tap_drag_lock": "disabled",
                    "accel_speed": 0.0,
                    "accel_profile": "none",
                    "natural_scroll", "disabled",
                    "left_handed": "disabled",
                    "click_method": "button_areas",
                    "middle_emulation": "disabled",
                    "scroll_method": "edge",
                    "dwt": "enabled",
                    "dwtp": "enabled"
               }
          },
          {
               "identifier": "3034:22494:USB2.0_VGA_UVC_WebCam:_USB2.0_V",
               "name": "USB2.0 VGA UVC WebCam: USB2.0 V",
               "vendor": 3034,
               "product": 22494,
               "type": "keyboard",
               "xkb_active_layout_name": "English (US)",
               "libinput": {
                    "send_events": "enabled"
               }
          },
          {
               "identifier": "0:3:Sleep_Button",
               "name": "Sleep Button",
               "vendor": 0,
               "product": 3,
               "type": "keyboard",
               "xkb_active_layout_name": "English (US)",
               "libinput": {
                    "send_events": "enabled"
               }
          },
          {
               "identifier": "0:5:Lid_Switch",
               "name": "Lid Switch",
               "vendor": 0,
               "product": 5,
               "type": "switch",
               "libinput": {
                    "send_events": "enabled"
               }
          },
          {
               "identifier": "0:6:Video_Bus",
               "name": "Video Bus",
               "vendor": 0,
               "product": 6,
               "type": "keyboard",
               "xkb_active_layout_name": "English (US)",
               "libinput": {
                    "send_events": "enabled"
               }
          },
          {
               "identifier": "0:1:Power_Button",
               "name": "Power Button",
               "vendor": 0,
               "product": 1,
               "type": "keyboard",
               "xkb_active_layout_name": "English (US)",
               "libinput": {
                    "send_events": "enabled"
               }
          }
     ]

🌸 101. GET_SEATS 🌸

MESSAGE

okay so this one just asks sway for a list of all the seats it's got configured rn. That's it. That's the ask. πŸͺ‘

REPLY

You get back an array of objects, one per seat. And bestie, there will always be at least one seat β€” no empty-array situation here, ever. Each of those objects is serving these properties:

  • name β€” string β€” the unique name for the seat πŸ’–
  • capabilities β€” integer β€” the number of capabilities that the seat has
  • focus β€” integer β€” the id of the node currently focused by the seat, or 0 when the seat is not currently focused by a node (i.e. a surface layer or xwayland unmanaged has focus) 🎯
  • devices β€” array β€” an array of input devices that are attached to the seat. Currently, this is an array of objects that are identical to those returned by GET_INPUTS πŸ‘‘

Example Reply:

     [
          {
               "name": "seat0",
               "capabilities": 3,
               "focus": 7,
               "devices": [
                    {
                         "identifier": "1:1:AT_Translated_Set_2_keyboard",
                         "name": "AT Translated Set 2 keyboard",
                         "vendor": 1,
                         "product": 1,
                         "type": "keyboard",
                         "xkb_active_layout_name": "English (US)",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    },
                    {
                         "identifier": "1267:5:Elan_Touchpad",
                         "name": "Elan Touchpad",
                         "vendor": 1267,
                         "product": 5,
                         "type": "pointer",
                         "libinput": {
                              "send_events": "enabled",
                              "tap": "enabled",
                              "tap_button_map": "lmr",
                              "tap_drag": "enabled",
                              "tap_drag_lock": "disabled",
                              "accel_speed": 0.0,
                              "accel_profile": "none",
                              "natural_scroll", "disabled",
                              "left_handed": "disabled",
                              "click_method": "button_areas",
                              "middle_emulation": "disabled",
                              "scroll_method": "edge",
                              "dwt": "enabled",
                              "dwtp": "enabled"
                         }
                    },
                    {
                         "identifier": "3034:22494:USB2.0_VGA_UVC_WebCam:_USB2.0_V",
                         "name": "USB2.0 VGA UVC WebCam: USB2.0 V",
                         "vendor": 3034,
                         "product": 22494,
                         "type": "keyboard",
                         "xkb_active_layout_name": "English (US)",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    },
                    {
                         "identifier": "0:3:Sleep_Button",
                         "name": "Sleep Button",
                         "vendor": 0,
                         "product": 3,
                         "type": "keyboard",
                         "xkb_active_layout_name": "English (US)",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    },
                    {
                         "identifier": "0:5:Lid_Switch",
                         "name": "Lid Switch",
                         "vendor": 0,
                         "product": 5,
                         "type": "switch",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    },
                    {
                         "identifier": "0:6:Video_Bus",
                         "name": "Video Bus",
                         "vendor": 0,
                         "product": 6,
                         "type": "keyboard",
                         "xkb_active_layout_name": "English (US)",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    },
                    {
                         "identifier": "0:1:Power_Button",
                         "name": "Power Button",
                         "vendor": 0,
                         "product": 1,
                         "type": "keyboard",
                         "xkb_active_layout_name": "English (US)",
                         "libinput": {
                              "send_events": "enabled"
                         }
                    }
               ]
          }
     ]

πŸ‘‘ EVENTS πŸ‘‘

so events are literally just sway's way of sliding into your client's DMs to tell you something changed. πŸ’… A client can subscribe to any events it wants to be notified of changes for β€” pick your faves, no pressure. And the event arrives in the exact same format as a reply, which is honestly so convenient of it. ✨

Here's what's on the menu rn:

okay so here’s the event-type lineup, bestie β€” exact codes, names, and what they mean, no cap ✨

  • 0x80000000 β€” workspace β€” Sent whenever an event involving a workspace occurs such as initialization of a new workspace or another workspace gaining focus πŸ’–
  • 0x80000001 β€” output β€” Sent when outputs are updated 🌸
  • 0x80000002 β€” mode β€” Sent whenever the binding mode changes πŸŽ€
  • 0x80000003 β€” window β€” Sent whenever an event involving a window occurs such as it being reparented, focused, or closed πŸͺŸ
  • 0x80000004 β€” barconfig_update β€” Sent whenever a bar config changes πŸ“
  • 0x80000005 β€” binding β€” Sent when a configured binding is executed πŸ’…
  • 0x80000006 β€” shutdown β€” Sent when the ipc shuts down because sway is exiting πŸ’€
  • 0x80000007 β€” tick β€” Sent when an ipc client sends a SEND_TICK message ⭐
  • 0x80000014 β€” bar_state_update β€” Sent when the visibility of a bar should change due to a modifier 🌈
  • 0x80000015 β€” input β€” Sent when something related to input devices changes πŸ¦‹

0x80000000. WORKSPACE

Sent whenever a change involving a workspace occurs. The event consists of a single object with the following properties:

  • change β€” string β€” The type of change that occurred. See below for more information πŸ”₯
  • current β€” object β€” An object representing the affected workspace or null for reload changes 🫢
  • old β€” object β€” For a focus change, this will be an object representing the workspace being switched from. Otherwise, it is null 😭

The following change types are currently available:

  • init β€” The workspace was created ✨
  • empty β€” The workspace is empty and is being destroyed since it is not visible πŸ’€
  • focus β€” The workspace was focused. See the old property for the previous focus πŸ‘‘
  • move β€” The workspace was moved to a different output 🚚
  • rename β€” The workspace was renamed 🏷️
  • urgent β€” A window on the workspace has had its urgency hint set or all urgency hints for windows on the workspace have been cleared 🚨
  • reload β€” The configuration file has been reloaded πŸ”„

Example Event:

{
     "change": "init",
     "old": null,
     "current": {
          "id": 10,
          "name": "2",
          "rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "focused": false,
          "focus": [
          ],
          "border": "none",
          "current_border_width": 0,
          "layout": "splith",
          "percent": null,
          "window_rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "deco_rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "geometry": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "window": null,
          "urgent": false,
          "floating_nodes": [
          ],
          "num": 2,
          "output": "eDP-1",
          "type": "workspace",
          "representation": null,
          "nodes": [
          ]
     }
}

0x80000001. OUTPUT

Sent whenever an output is added, removed, or its configuration is changed. The event is a single object with the property change, which is a string containing the reason for the change. Currently, the only value for change is unspecified.

Example Event:

{
     "change": "unspecified"
}

0x80000002. MODE

Sent whenever the binding mode changes. The event consists of a single object with the following properties:

  • change (string) β€” the binding mode that became active
  • pango_markup (boolean) β€” whether that mode should be parsed as pango markup or not

Example event, bestie, so you know exactly what it looks like:

{
     "change": "default",
     "pango_markup": false
}

0x80000003. WINDOW πŸ‘‘

Sent whenever literally anything happens to a window. The event is one single object with these properties:

  • change (string) β€” the type of change that occurred. Full list is right below πŸ’…
  • container (object) β€” an object representing the affected window

And here's the change types you can get rn:

  • new β€” the window was created ✨
  • close β€” the window was closed πŸ’€
  • focus β€” the window was focused
  • title β€” the window's title has changed
  • fullscreen_mode β€” the window's fullscreen mode has changed
  • move β€” the window has been reparented in the tree
  • floating β€” the window has become floating or is no longer floating
  • urgent β€” the window's urgency hint has changed status
  • mark β€” a mark has been added or removed from the window

Example event (yes it's a whole meal, just roll with it):

{
     "change": "new",
     "container": {
          "id": 12,
          "name": null,
          "rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "focused": false,
          "focus": [
          ],
          "border": "none",
          "current_border_width": 0,
          "layout": "none",
          "percent": 0.0,
          "window_rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "deco_rect": {
               "x": 0,
               "y": 0,
               "width": 0,
               "height": 0
          },
          "geometry": {
               "x": 0,
               "y": 0,
               "width": 1124,
               "height": 422
          },
          "window": 4194313,
          "urgent": false,
          "floating_nodes": [
          ],
          "type": "con",
          "pid": 19787,
          "app_id": null,
          "window_properties": {
               "class": "URxvt",
               "instance": "urxvt",
               "transient_for": null
          },
          "nodes": [
          ]
     }
}

0x80000004. BARCONFIG_UPDATE πŸŽ€

Sent whenever a config for a bar changes. The event is identical to the one you get from GET_BAR_CONFIG when a bar ID is given as a payload β€” so go peek at section 6, GET_BAR_CONFIG (WITH A PAYLOAD), above for the deets. No cap, it's the same thing.

0x80000005. BINDING ⌨️

Sent whenever a binding is executed. The event is a single object with these properties:

  • change (string) β€” the change that occurred for the binding. Currently this will only be run
  • command (string) β€” the command associated with the binding
  • event_state_mask (array) β€” an array of strings that correspond to each modifier key for the binding
  • input_code (integer) β€” for keyboard bindcodes, this is the key code for the binding. For mouse bindings, this is the X11 button number, if there is an equivalent. In all other cases, this will be 0.
  • symbol (string) β€” for keyboard bindsyms, this is the bindsym for the binding. Otherwise, this will be null
  • input_type (string) β€” the input type that triggered the binding. This is either keyboard or mouse

Example event:

{
     "change": "run",
     "binding": {
          "command": "workspace 2",
          "event_state_mask": [
               "Mod4"
          ],
          "input_code": 0,
          "symbol": "2",
          "input_type": "keyboard"
     }
}

0x80000006. SHUTDOWN 🫢

Sent whenever the IPC is shutting down. The event is a single object with the property change, which is a string containing the reason for the shutdown. Currently, the only value for change is exit, which is issued when sway is exiting. Like, that's it, that's the whole vibe check.

Example event:

{
     "change": "exit"
}

0x80000007. TICK ⏰

Sent when first subscribing to tick events or by a SEND_TICK message. The event is a single object with the following properties:

  • first (boolean) β€” whether this event got triggered by you subscribing to the tick events πŸ’«
  • payload (string) β€” the payload that came in a SEND_TICK message, if there was one. No payload? Then it's an empty string, simple as that.

Example Event, copy-paste realness:

{
     "first": true
     "payload": ""
}

πŸ’₯ 0x80000014. BAR_STATE_UPDATE πŸ’₯

Fires when a bar's visibility changes because somebody pressed a modifier. The event is a single object, and it's giving these properties:

  • id (string) β€” the bar ID that got affected πŸŽ€
  • visible_by_modifier (boolean) β€” whether the bar should be made visible because a modifier is being pressed

Example Event, periodt:

{
     "id": "bar-0",
     "visible_by_modifier": true
}

⌨️ 0x80000015. INPUT ⌨️

Sent whenever something input-device-related changes. Single object, here's the tea:

  • change (string) β€” what actually changed
  • input (object) β€” an object representing the input, and it's literally identical to the ones GET_INPUTS gives you (yes, same shape, no cap) 🫢

The change types you can get right now:

  • added β€” the input device became available ✨
  • removed β€” the input device is no longer available 😭
  • xkb_keymap β€” (keyboards only) the keymap for the keyboard changed
  • xkb_layout β€” (keyboards only) the effective layout in the keymap changed
  • libinput_config β€” (libinput device only) a libinput config option for the device changed

Example Event, and yes this one is a whole meal:

{
     "change": "xkb_layout",
     "input": {
          "identifier": "1:1:AT_Translated_Set_2_keyboard",
          "name": "AT Translated Set 2 keyboard",
          "vendor": 1,
          "product": 1,
          "type": "keyboard",
          "xkb_layout_names": [
               "English (US)",
               "English (Dvorak)"
          ],
          "xkb_active_layout_index": 1,
          "xkb_active_layout_name": "English (Dvorak)",
          "libinput": {
               "send_events": "enabled"
          }
     }
}

🌈 SEE ALSO 🌈

Go read these next, bestie, they're the whole friend group:


aaaand that's the whole page, we ate and left zero crumbs πŸ’…βœ¨ This lil masterpiece is from 2026-04-26 and lives under the name sway-ipc(7) β€” go forth and script something iconic, ily, bye! πŸŽ€πŸ¦‹πŸ’œ

πŸ“¦ where this page comes from