]> git.sur5r.net Git - i3/i3.github.io/blobdiff - _docs/ipc
update docs for 4.15
[i3/i3.github.io] / _docs / ipc
index 7e71326022606aa2b4d1abf93d4d77d3c448fe1a..8b767adebffa127bab432c2c9607b57ce491567b 100644 (file)
--- a/_docs/ipc
+++ b/_docs/ipc
@@ -1,7 +1,7 @@
 IPC interface (interprocess communication)
 ==========================================
-Michael Stapelberg <michael+i3@stapelberg.de>
-March 2010
+Michael Stapelberg <michael@i3wm.org>
+September 2017
 
 This document describes how to interface with i3 from a separate process. This
 is useful for example to remote-control i3 (to write test cases for example) or
@@ -11,12 +11,21 @@ workspace bar.
 The method of choice for IPC in our case is a unix socket because it has very
 little overhead on both sides and is usually available without headaches in
 most languages. In the default configuration file, the ipc-socket gets created
-in +/tmp/i3-%u/ipc-socket.%p+ where +%u+ is your UNIX username and +%p+ is the
-PID of i3.
+in +/tmp/i3-%u.XXXXXX/ipc-socket.%p+ where +%u+ is your UNIX username, +%p+ is
+the PID of i3 and XXXXXX is a string of random characters from the portable
+filename character set (see mkdtemp(3)). You can get the socketpath from i3 by
+calling +i3 --get-socketpath+.
 
 All i3 utilities, like +i3-msg+ and +i3-input+ will read the +I3_SOCKET_PATH+
 X11 property, stored on the X11 root window.
 
+[WARNING]
+.Use an existing library!
+There are existing libraries for many languages. You can have a look at
+<<libraries>> or search the web if your language of choice is not mentioned.
+Usually, it is not necessary to implement low-level communication with i3
+directly.
+
 == Establishing a connection
 
 To establish a connection, simply open the IPC socket. The following code
@@ -24,7 +33,8 @@ snippet illustrates this in Perl:
 
 -------------------------------------------------------------
 use IO::Socket::UNIX;
-my $sock = IO::Socket::UNIX->new(Peer => '/tmp/i3-ipc.sock');
+chomp(my $path = qx(i3 --get-socketpath));
+my $sock = IO::Socket::UNIX->new(Peer => $path);
 -------------------------------------------------------------
 
 == Sending messages to i3
@@ -40,25 +50,22 @@ The magic string currently is "i3-ipc" and will only be changed when a change
 in the IPC API is done which breaks compatibility (we hope that we don’t need
 to do that).
 
-Currently implemented message types are the following:
-
-COMMAND (0)::
-       The payload of the message is a command for i3 (like the commands you
-       can bind to keys in the configuration file) and will be executed
-       directly after receiving it. There is no reply to this message.
-GET_WORKSPACES (1)::
-       Gets the current workspaces. The reply will be a JSON-encoded list of
-       workspaces (see the reply section).
-SUBSCRIBE (2)::
-       Subscribes your connection to certain events. See <<events>> for a
-       description of this message and the concept of events.
-GET_OUTPUTS (3)::
-       Gets the current outputs. The reply will be a JSON-encoded list of outputs
-       (see the reply section).
-GET_TREE (4)::
-       Gets the layout tree. i3 uses a tree as data structure which includes
-       every container. The reply will be the JSON-encoded tree (see the reply
-       section).
+.Currently implemented message types
+[options="header",cols="^10%,^20%,^20%,^50%"]
+|======================================================
+| Type (numeric) | Type (name) | Reply type | Purpose
+| 0 | +RUN_COMMAND+ | <<_command_reply,COMMAND>> | Run the payload as an i3 command (like the commands you can bind to keys).
+| 1 | +GET_WORKSPACES+ | <<_workspaces_reply,WORKSPACES>> | Get the list of current workspaces.
+| 2 | +SUBSCRIBE+ | <<_subscribe_reply,SUBSCRIBE>> | Subscribe this IPC connection to the event types specified in the message payload. See <<events>>.
+| 3 | +GET_OUTPUTS+ | <<_outputs_reply,OUTPUTS>> | Get the list of current outputs.
+| 4 | +GET_TREE+ | <<_tree_reply,TREE>> | Get the i3 layout tree.
+| 5 | +GET_MARKS+ | <<_marks_reply,MARKS>> | Gets the names of all currently set marks.
+| 6 | +GET_BAR_CONFIG+ | <<_bar_config_reply,BAR_CONFIG>> | Gets the specified bar configuration or the names of all bar configurations if payload is empty.
+| 7 | +GET_VERSION+ | <<_version_reply,VERSION>> | Gets the i3 version.
+| 8 | +GET_BINDING_MODES+ | <<_binding_modes_reply,BINDING_MODES>> | Gets the names of all currently configured binding modes.
+| 9 | +GET_CONFIG+ | <<_config_reply,CONFIG>> | Returns the last loaded i3 config.
+| 10 | +SEND_TICK+ | <<_tick_reply,TICK>> | Sends a tick event with the specified payload.
+|======================================================
 
 So, a typical message could look like this:
 --------------------------------------------------
@@ -68,7 +75,7 @@ So, a typical message could look like this:
 Or, as a hexdump:
 ------------------------------------------------------------------------------
 00000000  69 33 2d 69 70 63 04 00  00 00 00 00 00 00 65 78  |i3-ipc........ex|
-00000010  69 74 0a                                          |it.|
+00000010  69 74                                             |it|
 ------------------------------------------------------------------------------
 
 To generate and send such a message, you could use the following code in Perl:
@@ -101,34 +108,49 @@ payload.
 The following reply types are implemented:
 
 COMMAND (0)::
-       Confirmation/Error code for the COMMAND message.
-GET_WORKSPACES (1)::
+       Confirmation/Error code for the RUN_COMMAND message.
+WORKSPACES (1)::
        Reply to the GET_WORKSPACES message.
 SUBSCRIBE (2)::
        Confirmation/Error code for the SUBSCRIBE message.
-GET_OUTPUTS (3)::
+OUTPUTS (3)::
        Reply to the GET_OUTPUTS message.
-GET_TREE (4)::
+TREE (4)::
        Reply to the GET_TREE message.
-
+MARKS (5)::
+       Reply to the GET_MARKS message.
+BAR_CONFIG (6)::
+       Reply to the GET_BAR_CONFIG message.
+VERSION (7)::
+       Reply to the GET_VERSION message.
+BINDING_MODES (8)::
+        Reply to the GET_BINDING_MODES message.
+GET_CONFIG (9)::
+       Reply to the GET_CONFIG message.
+TICK (10)::
+       Reply to the SEND_TICK message.
+
+[[_command_reply]]
 === COMMAND reply
 
-The reply consists of a single serialized map. At the moment, the only
-property is +success (bool)+, but this will be expanded in future versions.
+The reply consists of a list of serialized maps for each command that was
+parsed. Each has the property +success (bool)+ and may also include a
+human-readable error message in the property +error (string)+.
 
 *Example:*
 -------------------
-{ "success": true }
+[{ "success": true }]
 -------------------
 
-=== GET_WORKSPACES reply
+[[_workspaces_reply]]
+=== WORKSPACES reply
 
 The reply consists of a serialized list of workspaces. Each workspace has the
 following properties:
 
 num (integer)::
        The logical number of the workspace. Corresponds to the command
-       to switch to this workspace.
+       to switch to this workspace. For named workspaces, this will be -1.
 name (string)::
        The name of this workspace (by default num+1), as changed by the
        user. Encoded in UTF-8.
@@ -180,6 +202,7 @@ output (string)::
 ]
 -------------------
 
+[[_subscribe_reply]]
 === SUBSCRIBE reply
 
 The reply consists of a single serialized map. The only property is
@@ -191,7 +214,8 @@ default) or whether a JSON parse error occurred.
 { "success": true }
 -------------------
 
-=== GET_OUTPUTS reply
+[[_outputs_reply]]
+=== OUTPUTS reply
 
 The reply consists of a serialized list of outputs. Each output has the
 following properties:
@@ -200,9 +224,11 @@ name (string)::
        The name of this output (as seen in +xrandr(1)+). Encoded in UTF-8.
 active (boolean)::
        Whether this output is currently active (has a valid mode).
-current_workspace (integer)::
-       The current workspace which is visible on this output. +null+ if the
-       output is not active.
+primary (boolean)::
+       Whether this output is currently the primary output.
+current_workspace (string)::
+       The name of the current workspace that is visible on this output. +null+ if
+       the output is not active.
 rect (map)::
        The rectangle of this output (equals the rect of the output it
        is on), consists of x, y, width, height.
@@ -213,7 +239,7 @@ rect (map)::
  {
   "name": "LVDS1",
   "active": true,
-  "current_workspace": 4,
+  "current_workspace": "4",
   "rect": {
    "x": 0,
    "y": 0,
@@ -224,18 +250,19 @@ rect (map)::
  {
   "name": "VGA1",
   "active": true,
-  "current_workspace": 1,
+  "current_workspace": "1",
   "rect": {
    "x": 1280,
    "y": 0,
    "width": 1280,
    "height": 1024
-  },
+  }
  }
 ]
 -------------------
 
-=== GET_TREE reply
+[[_tree_reply]]
+=== TREE reply
 
 The reply consists of a serialized tree. Each node in the tree (representing
 one container) has at least the properties listed below. While the nodes might
@@ -250,17 +277,27 @@ name (string)::
        The internal name of this container. For all containers which are part
        of the tree structure down to the workspace contents, this is set to a
        nice human-readable name of the container.
+       For containers that have an X11 window, the content is the title
+       (_NET_WM_NAME property) of that window.
        For all other containers, the content is not defined (yet).
+type (string)::
+       Type of this container. Can be one of "root", "output", "con",
+       "floating_con", "workspace" or "dockarea".
 border (string)::
-       Can be either "normal", "none" or "1pixel", dependending on the
+       Can be either "normal", "none" or "pixel", depending on the
        container’s border style.
+current_border_width (integer)::
+       Number of pixels of the border width.
 layout (string)::
-       Can be either "default", "stacked", "tabbed", "dockarea" or "output".
+       Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or
+       "output".
        Other values might be possible in the future, should we add new
        layouts.
 orientation (string)::
        Can be either "none" (for non-split containers), "horizontal" or
        "vertical".
+       THIS FIELD IS OBSOLETE. It is still present, but your code should not
+       use it. Instead, rely on the layout field.
 percent (float)::
        The percentage which this container takes in its parent. A value of
        +null+ means that the percent property does not make sense for this
@@ -278,13 +315,35 @@ window_rect (map)::
        So, when using the +default+ layout, you will have a 2 pixel border on
        each side, making the window_rect +{ "x": 2, "y": 0, "width": 632,
        "height": 366 }+ (for example).
+deco_rect (map)::
+       The coordinates of the *window decoration* inside its container. These
+       coordinates are relative to the container and do not include the actual
+       client window.
 geometry (map)::
        The original geometry the window specified when i3 mapped it. Used when
        switching a window to floating mode, for example.
+window (integer)::
+       The X11 window ID of the *actual client window* inside this container.
+       This field is set to null for split containers or otherwise empty
+       containers. This ID corresponds to what xwininfo(1) and other
+       X11-related tools display (usually in hex).
 urgent (bool)::
-       Whether this container (window or workspace) has the urgency hint set.
+       Whether this container (window, split container, floating container or
+       workspace) has the urgency hint set, directly or indirectly. All parent
+       containers up until the workspace container will be marked urgent if they
+       have at least one urgent child.
 focused (bool)::
        Whether this container is currently focused.
+focus (array of integer)::
+       List of child node IDs (see +nodes+, +floating_nodes+ and +id+) in focus
+       order. Traversing the tree by following the first entry in this array
+       will result in eventually reaching the one node with +focused+ set to
+       true.
+nodes (array of node)::
+       The tiling (i.e. non-floating) child containers of this node.
+floating_nodes (array of node)::
+       The floating child containers of this node. Only non-empty on nodes with
+       type +workspace+.
 
 Please note that in the following example, I have left out some keys/values
 which are not relevant for the type of the node. Otherwise, the example would
@@ -339,7 +398,7 @@ JSON dump:
         "y": 0,
         "width": 1280,
         "height": 0
-       },
+       }
       },
 
       {
@@ -418,6 +477,182 @@ JSON dump:
 }
 ------------------------
 
+[[_marks_reply]]
+=== MARKS reply
+
+The reply consists of a single array of strings for each container that has a
+mark. A mark can only be set on one container, so the array is unique.
+The order of that array is undefined.
+
+If no window has a mark the response will be the empty array [].
+
+[[_bar_config_reply]]
+=== BAR_CONFIG reply
+
+This can be used by third-party workspace bars (especially i3bar, but others
+are free to implement compatible alternatives) to get the +bar+ block
+configuration from i3.
+
+Depending on the input, the reply is either:
+
+empty input::
+       An array of configured bar IDs
+Bar ID::
+       A JSON map containing the configuration for the specified bar.
+
+Each bar configuration has the following properties:
+
+id (string)::
+       The ID for this bar. Included in case you request multiple
+       configurations and want to differentiate the different replies.
+mode (string)::
+       Either +dock+ (the bar sets the dock window type) or +hide+ (the bar
+       does not show unless a specific key is pressed).
+position (string)::
+       Either +bottom+ or +top+ at the moment.
+status_command (string)::
+       Command which will be run to generate a statusline. Each line on stdout
+       of this command will be displayed in the bar. At the moment, no
+       formatting is supported.
+font (string)::
+       The font to use for text on the bar.
+workspace_buttons (boolean)::
+       Display workspace buttons or not? Defaults to true.
+binding_mode_indicator (boolean)::
+       Display the mode indicator or not? Defaults to true.
+verbose (boolean)::
+       Should the bar enable verbose output for debugging? Defaults to false.
+colors (map)::
+       Contains key/value pairs of colors. Each value is a color code in hex,
+       formatted #rrggbb (like in HTML).
+
+The following colors can be configured at the moment:
+
+background::
+       Background color of the bar.
+statusline::
+       Text color to be used for the statusline.
+separator::
+       Text color to be used for the separator.
+focused_background::
+       Background color of the bar on the currently focused monitor output.
+focused_statusline::
+       Text color to be used for the statusline on the currently focused
+       monitor output.
+focused_separator::
+       Text color to be used for the separator on the currently focused
+       monitor output.
+focused_workspace_text/focused_workspace_bg/focused_workspace_border::
+       Text/background/border color for a workspace button when the workspace
+       has focus.
+active_workspace_text/active_workspace_bg/active_workspace_border::
+       Text/background/border color for a workspace button when the workspace
+       is active (visible) on some output, but the focus is on another one.
+       You can only tell this apart from the focused workspace when you are
+       using multiple monitors.
+inactive_workspace_text/inactive_workspace_bg/inactive_workspace_border::
+       Text/background/border color for a workspace button when the workspace
+       does not have focus and is not active (visible) on any output. This
+       will be the case for most workspaces.
+urgent_workspace_text/urgent_workspace_bg/urgent_workspace_border::
+       Text/background/border color for workspaces which contain at least one
+       window with the urgency hint set.
+binding_mode_text/binding_mode_bg/binding_mode_border::
+        Text/background/border color for the binding mode indicator.
+
+
+*Example of configured bars:*
+--------------
+["bar-bxuqzf"]
+--------------
+
+*Example of bar configuration:*
+--------------
+{
+ "id": "bar-bxuqzf",
+ "mode": "dock",
+ "position": "bottom",
+ "status_command": "i3status",
+ "font": "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1",
+ "workspace_buttons": true,
+ "binding_mode_indicator": true,
+ "verbose": false,
+ "colors": {
+   "background": "#c0c0c0",
+   "statusline": "#00ff00",
+   "focused_workspace_text": "#ffffff",
+   "focused_workspace_bg": "#000000"
+ }
+}
+--------------
+
+[[_version_reply]]
+=== VERSION reply
+
+The reply consists of a single JSON dictionary with the following keys:
+
+major (integer)::
+       The major version of i3, such as +4+.
+minor (integer)::
+       The minor version of i3, such as +2+. Changes in the IPC interface (new
+       features) will only occur with new minor (or major) releases. However,
+       bugfixes might be introduced in patch releases, too.
+patch (integer)::
+       The patch version of i3, such as +1+ (when the complete version is
+       +4.2.1+). For versions such as +4.2+, patch will be set to +0+.
+human_readable (string)::
+       A human-readable version of i3 containing the precise git version,
+       build date and branch name. When you need to display the i3 version to
+       your users, use the human-readable version whenever possible (since
+       this is what +i3 --version+ displays, too).
+loaded_config_file_name (string)::
+       The current config path.
+
+*Example:*
+-------------------
+{
+   "human_readable" : "4.2-169-gf80b877 (2012-08-05, branch \"next\")",
+   "loaded_config_file_name" : "/home/hwangcc23/.i3/config",
+   "minor" : 2,
+   "patch" : 0,
+   "major" : 4
+}
+-------------------
+
+[[_binding_modes_reply]]
+=== BINDING_MODES reply
+
+The reply consists of an array of all currently configured binding modes.
+
+*Example:*
+---------------------
+["default", "resize"]
+---------------------
+
+[[_config_reply]]
+=== CONFIG reply
+
+The config reply is a map which currently only contains the "config" member,
+which is a string containing the config file as loaded by i3 most recently.
+
+*Example:*
+-------------------
+{ "config": "font pango:monospace 8\nbindsym Mod4+q exit\n" }
+-------------------
+
+[[_tick_reply]]
+=== TICK reply
+
+The reply is a map containing the "success" member. After the reply was
+received, the tick event has been written to all IPC connections which subscribe
+to tick events. UNIX sockets are usually buffered, but you can be certain that
+once you receive the tick event you just triggered, you must have received all
+events generated prior to the +SEND_TICK+ message (happened-before relation).
+
+*Example:*
+-------------------
+{ "success": true }
+-------------------
 
 == Events
 
@@ -445,7 +680,7 @@ you can register to an event.
 *Example:*
 ---------------------------------
 type: SUBSCRIBE
-payload: [ "workspace", "focus" ]
+payload: [ "workspace", "output" ]
 ---------------------------------
 
 
@@ -461,6 +696,24 @@ workspace (0)::
 output (1)::
        Sent when RandR issues a change notification (of either screens,
        outputs, CRTCs or output properties).
+mode (2)::
+       Sent whenever i3 changes its binding mode.
+window (3)::
+       Sent when a client's window is successfully reparented (that is when i3
+       has finished fitting it into a container), when a window received input
+       focus or when certain properties of the window have changed.
+barconfig_update (4)::
+    Sent when the hidden_state or mode field in the barconfig of any bar
+    instance was updated and when the config is reloaded.
+binding (5)::
+       Sent when a configured command binding is triggered with the keyboard or
+       mouse
+shutdown (6)::
+       Sent when the ipc shuts down because of a restart or exit by user command
+tick (7)::
+       Sent when the ipc client subscribes to the tick event (with +"first":
+       true+) or when any ipc client sends a SEND_TICK message (with +"first":
+       false+).
 
 *Example:*
 --------------------------------------------------------------------
@@ -484,11 +737,32 @@ if ($is_event) {
 
 This event consists of a single serialized map containing a property
 +change (string)+ which indicates the type of the change ("focus", "init",
-"empty", "urgent").
+"empty", "urgent", "reload", "rename", "restored", "move"). A
++current (object)+ property will be present with the affected workspace
+whenever the type of event affects a workspace (otherwise, it will be +null).
+
+When the change is "focus", an +old (object)+ property will be present with the
+previous workspace.  When the first switch occurs (when i3 focuses the
+workspace visible at the beginning) there is no previous workspace, and the
++old+ property will be set to +null+.  Also note that if the previous is empty
+it will get destroyed when switching, but will still be present in the "old"
+property.
 
 *Example:*
 ---------------------
-{ "change": "focus" }
+{
+ "change": "focus",
+ "current": {
+  "id": 28489712,
+  "type": "workspace",
+  ...
+ }
+ "old": {
+  "id": 28489715,
+  "type": "workspace",
+  ...
+ }
+}
 ---------------------
 
 === output event
@@ -502,18 +776,230 @@ This event consists of a single serialized map containing a property
 { "change": "unspecified" }
 ---------------------------
 
-== See also
+=== mode event
+
+This event consists of a single serialized map containing a property
++change (string)+ which holds the name of current mode in use. The name
+is the same as specified in config when creating a mode. The default
+mode is simply named default. It contains a second property, +pango_markup+, which
+defines whether pango markup shall be used for displaying this mode.
+
+*Example:*
+---------------------------
+{
+  "change": "default",
+  "pango_markup": true
+}
+---------------------------
+
+=== window event
+
+This event consists of a single serialized map containing a property
++change (string)+ which indicates the type of the change
+
+* +new+ – the window has become managed by i3
+* +close+ – the window has closed
+* +focus+ – the window has received input focus
+* +title+ – the window's title has changed
+* +fullscreen_mode+ – the window has entered or exited fullscreen mode
+* +move+ – the window has changed its position in the tree
+* +floating+ – the window has transitioned to or from floating
+* +urgent+ – the window has become urgent or lost its urgent status
+* +mark+ – a mark has been added to or removed from the window
+
+Additionally a +container (object)+ field will be present, which consists
+of the window's parent container. Be aware that for the "new" event, the
+container will hold the initial name of the newly reparented window (e.g.
+if you run urxvt with a shell that changes the title, you will still at
+this point get the window title as "urxvt").
+
+*Example:*
+---------------------------
+{
+ "change": "new",
+ "container": {
+  "id": 35569536,
+  "type": "con",
+  ...
+ }
+}
+---------------------------
+
+=== barconfig_update event
+
+This event consists of a single serialized map reporting on options from the
+barconfig of the specified bar_id that were updated in i3. This event is the
+same as a +GET_BAR_CONFIG+ reply for the bar with the given id.
+
+=== binding event
+
+This event consists of a single serialized map reporting on the details of a
+binding that ran a command because of user input. The +change (string)+ field
+indicates what sort of binding event was triggered (right now it will always be
++"run"+ but may be expanded in the future).
+
+The +binding (object)+ field contains details about the binding that was run:
+
+command (string)::
+       The i3 command that is configured to run for this binding.
+event_state_mask (array of strings)::
+       The group and modifier keys that were configured with this binding.
+input_code (integer)::
+       If the binding was configured with +bindcode+, this will be the key code
+       that was given for the binding. If the binding is a mouse binding, it will be
+       the number of the mouse button that was pressed. Otherwise it will be 0.
+symbol (string or null)::
+       If this is a keyboard binding that was configured with +bindsym+, this
+       field will contain the given symbol. Otherwise it will be +null+.
+input_type (string)::
+       This will be +"keyboard"+ or +"mouse"+ depending on whether or not this was
+       a keyboard or a mouse binding.
+
+*Example:*
+---------------------------
+{
+ "change": "run",
+ "binding": {
+  "command": "nop",
+  "event_state_mask": [
+    "shift",
+    "ctrl"
+  ],
+  "input_code": 0,
+  "symbol": "t",
+  "input_type": "keyboard"
+ }
+}
+---------------------------
+
+=== shutdown event
+
+This event is triggered when the connection to the ipc is about to shutdown
+because of a user action such as a +restart+ or +exit+ command. The +change
+(string)+ field indicates why the ipc is shutting down. It can be either
++"restart"+ or +"exit"+.
+
+*Example:*
+---------------------------
+{
+ "change": "restart"
+}
+---------------------------
+
+=== tick event
+
+This event is triggered by a subscription to tick events or by a +SEND_TICK+
+message.
+
+*Example (upon subscription):*
+--------------------------------------------------------------------------------
+{
+ "first": true,
+ "payload": ""
+}
+--------------------------------------------------------------------------------
+
+*Example (upon +SEND_TICK+ with a payload of +arbitrary string+):*
+--------------------------------------------------------------------------------
+{
+ "first": false,
+ "payload": "arbitrary string"
+}
+--------------------------------------------------------------------------------
+
+== See also (existing libraries)
+
+[[libraries]]
 
 For some languages, libraries are available (so you don’t have to implement
 all this on your own). This list names some (if you wrote one, please let me
 know):
 
 C::
-       i3 includes a headerfile +i3/ipc.h+ which provides you all constants.
-       However, there is no library yet.
-Ruby::
-       http://github.com/badboy/i3-ipc
+       * i3 includes a headerfile +i3/ipc.h+ which provides you all constants.
+       * https://github.com/acrisci/i3ipc-glib
+C++::
+       * https://github.com/drmgc/i3ipcpp
+Go::
+       * https://github.com/mdirkse/i3ipc-go
+       * https://github.com/i3/go-i3
+JavaScript::
+       * https://github.com/acrisci/i3ipc-gjs
+Lua::
+       * https://github.com/acrisci/i3ipc-lua
 Perl::
-       http://search.cpan.org/search?query=AnyEvent::I3
+       * https://metacpan.org/module/AnyEvent::I3
 Python::
-       http://github.com/thepub/i3ipc
+       * https://github.com/acrisci/i3ipc-python
+       * https://github.com/whitelynx/i3ipc (not maintained)
+       * https://github.com/ziberna/i3-py (not maintained)
+Ruby::
+       * https://github.com/veelenga/i3ipc-ruby
+       * https://github.com/badboy/i3-ipc (not maintained)
+Rust::
+       * https://github.com/tmerr/i3ipc-rs
+OCaml::
+       * https://github.com/Armael/ocaml-i3ipc
+
+== Appendix A: Detecting byte order in memory-safe languages
+
+Some programming languages such as Go don’t offer a way to serialize data in the
+native byte order of the machine they’re running on without resorting to tricks
+involving the +unsafe+ package.
+
+The following technique can be used (and will not be broken by changes to i3) to
+detect the byte order i3 is using:
+
+1. The byte order dependent fields of an IPC message are message type and
+   payload length.
+
+   * The message type +RUN_COMMAND+ (0) is the same in big and little endian, so
+     we can use it in either byte order to elicit a reply from i3.
+
+   * The payload length 65536 + 256 (+0x00 01 01 00+) is the same in big and
+     little endian, and also small enough to not worry about memory allocations
+     of that size. We must use payloads of length 65536 + 256 in every message
+     we send, so that i3 will be able to read the entire message regardless of
+     the byte order it uses.
+
+2. Send a big endian encoded message of type +SUBSCRIBE+ (2) with payload `[]`
+   followed by 65536 + 256 - 2 +SPACE+ (ASCII 0x20) bytes.
+
+   * If i3 is running in big endian, this message is treated as a noop,
+     resulting in a +SUBSCRIBE+ reply with payload `{"success":true}`
+     footnote:[A small payload is important: that way, we circumvent dealing
+     with UNIX domain socket buffer sizes, whose size depends on the
+     implementation/operating system. Exhausting such a buffer results in an i3
+     deadlock unless you concurrently read and write, which — depending on the
+     programming language — makes the technique much more complicated.].
+
+   * If i3 is running in little endian, this message is read in its entirety due
+     to the byte order independent payload length, then
+     https://github.com/i3/i3/blob/d726d09d496577d1c337a4b97486f2c9fbc914f1/src/ipc.c#L1188[silently
+     discarded] due to the unknown message type.
+
+3. Send a byte order independent message, i.e. type +RUN_COMMAND+ (0) with
+   payload +nop byte order detection. padding:+, padded to 65536 + 256 bytes
+   with +a+ (ASCII 0x61) bytes. i3 will reply to this message with a reply of
+   type +COMMAND+ (0).
+
+   * The human-readable prefix is in there to not confuse readers of the i3 log.
+
+   * This messages serves as a synchronization primitive so that we know whether
+     i3 discarded the +SUBSCRIBE+ message or didn’t answer it yet.
+
+4. Receive a message header from i3, decoding the message type as big endian.
+
+   * If the message’s reply type is +COMMAND+ (0), i3 is running in little
+     endian (because the +SUBSCRIBE+ message was discarded). Decode the message
+     payload length as little endian, receive the message payload.
+
+   * If the message’s reply type is anything else, i3 is running in big endian
+     (because our big endian encoded +SUBSCRIBE+ message was answered). Decode
+     the message payload length in big endian, receive the message
+     payload. Then, receive the pending +COMMAND+ message reply in big endian.
+
+5. From here on out, send/receive all messages using the detected byte order.
+
+Find an example implementation of this technique in
+https://github.com/i3/go-i3/blob/master/byteorder.go