]> git.sur5r.net Git - i3/i3/blobdiff - docs/ipc
Merge pull request #3329 from lasers/next
[i3/i3] / docs / ipc
index 75ea9179d3e6de7d0105a0d33b1e8f94b257f2a0..e44ffd7ce20f2c38230bef3e137e02f73a22ea0e 100644 (file)
--- a/docs/ipc
+++ b/docs/ipc
@@ -1,7 +1,7 @@
 IPC interface (interprocess communication)
 ==========================================
 Michael Stapelberg <michael@i3wm.org>
-October 2014
+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
@@ -63,6 +63,9 @@ to do that).
 | 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.
+| 11 | +SYNC+ | <<_sync_reply,SYNC>> | Sends an i3 sync event with the specified random value to the specified window.
 |======================================================
 
 So, a typical message could look like this:
@@ -123,6 +126,10 @@ 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
@@ -321,6 +328,8 @@ window (integer)::
        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).
+window_properties (map)::
+       X11 window properties title, instance, class, window_role and transient_for.
 urgent (bool)::
        Whether this container (window, split container, floating container or
        workspace) has the urgency hint set, directly or indirectly. All parent
@@ -416,6 +425,12 @@ JSON dump:
            "width": 1280,
            "height": 782
          },
+         "window_properties": {
+           "class": "Evince",
+           "instance": "evince",
+           "title": "Properties",
+           "transient_for": 52428808
+         },
          "floating_nodes": [],
          "nodes": [
 
@@ -623,6 +638,43 @@ The reply consists of an array of all currently configured binding modes.
 ["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 }
+-------------------
+
+[[_sync_reply]]
+=== SYNC reply
+
+The reply is a map containing the "success" member. After the reply was
+received, the https://i3wm.org/docs/testsuite.html#i3_sync[i3 sync message] was
+responded to.
+
+*Example:*
+-------------------
+{ "success": true }
+-------------------
+
 == Events
 
 [[events]]
@@ -679,6 +731,10 @@ binding (5)::
        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:*
 --------------------------------------------------------------------
@@ -851,6 +907,27 @@ because of a user action such as a +restart+ or +exit+ command. The +change
 }
 ---------------------------
 
+=== 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]]
@@ -866,6 +943,7 @@ 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::
@@ -883,3 +961,66 @@ 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