]> git.sur5r.net Git - i3/i3/blob - docs/ipc
Merge branch 'fix-focus-ipc'
[i3/i3] / docs / ipc
1 IPC interface (interprocess communication)
2 ==========================================
3 Michael Stapelberg <michael+i3@stapelberg.de>
4 March 2010
5
6 This document describes how to interface with i3 from a separate process. This
7 is useful for example to remote-control i3 (to write test cases for example) or
8 to get various information like the current workspaces to implement an external
9 workspace bar.
10
11 The method of choice for IPC in our case is a unix socket because it has very
12 little overhead on both sides and is usually available without headaches in
13 most languages. In the default configuration file, the ipc-socket gets created
14 in +/tmp/i3-%u/ipc-socket.%p+ where +%u+ is your UNIX username and +%p+ is the
15 PID of i3.
16
17 All i3 utilities, like +i3-msg+ and +i3-input+ will read the +I3_SOCKET_PATH+
18 X11 property, stored on the X11 root window.
19
20 == Establishing a connection
21
22 To establish a connection, simply open the IPC socket. The following code
23 snippet illustrates this in Perl:
24
25 -------------------------------------------------------------
26 use IO::Socket::UNIX;
27 my $sock = IO::Socket::UNIX->new(Peer => '/tmp/i3-ipc.sock');
28 -------------------------------------------------------------
29
30 == Sending messages to i3
31
32 To send a message to i3, you have to format in the binary message format which
33 i3 expects. This format specifies a magic string in the beginning to ensure
34 the integrity of messages (to prevent follow-up errors). Following the magic
35 string comes the length of the payload of the message as 32-bit integer, and
36 the type of the message as 32-bit integer (the integers are not converted, so
37 they are in native byte order).
38
39 The magic string currently is "i3-ipc" and will only be changed when a change
40 in the IPC API is done which breaks compatibility (we hope that we don’t need
41 to do that).
42
43 Currently implemented message types are the following:
44
45 COMMAND (0)::
46         The payload of the message is a command for i3 (like the commands you
47         can bind to keys in the configuration file) and will be executed
48         directly after receiving it. There is no reply to this message.
49 GET_WORKSPACES (1)::
50         Gets the current workspaces. The reply will be a JSON-encoded list of
51         workspaces (see the reply section).
52 SUBSCRIBE (2)::
53         Subscribes your connection to certain events. See <<events>> for a
54         description of this message and the concept of events.
55 GET_OUTPUTS (3)::
56         Gets the current outputs. The reply will be a JSON-encoded list of outputs
57         (see the reply section).
58 GET_TREE (4)::
59         Gets the layout tree. i3 uses a tree as data structure which includes
60         every container. The reply will be the JSON-encoded tree (see the reply
61         section).
62
63 So, a typical message could look like this:
64 --------------------------------------------------
65 "i3-ipc" <message length> <message type> <payload>
66 --------------------------------------------------
67
68 Or, as a hexdump:
69 ------------------------------------------------------------------------------
70 00000000  69 33 2d 69 70 63 04 00  00 00 00 00 00 00 65 78  |i3-ipc........ex|
71 00000010  69 74 0a                                          |it.|
72 ------------------------------------------------------------------------------
73
74 To generate and send such a message, you could use the following code in Perl:
75 ------------------------------------------------------------
76 sub format_ipc_command {
77     my ($msg) = @_;
78     my $len;
79     # Get the real byte count (vs. amount of characters)
80     { use bytes; $len = length($msg); }
81     return "i3-ipc" . pack("LL", $len, 0) . $msg;
82 }
83
84 $sock->write(format_ipc_command("exit"));
85 ------------------------------------------------------------------------------
86
87 == Receiving replies from i3
88
89 Replies from i3 usually consist of a simple string (the length of the string
90 is the message_length, so you can consider them length-prefixed) which in turn
91 contain the JSON serialization of a data structure. For example, the
92 GET_WORKSPACES message returns an array of workspaces (each workspace is a map
93 with certain attributes).
94
95 === Reply format
96
97 The reply format is identical to the normal message format. There also is
98 the magic string, then the message length, then the message type and the
99 payload.
100
101 The following reply types are implemented:
102
103 COMMAND (0)::
104         Confirmation/Error code for the COMMAND message.
105 GET_WORKSPACES (1)::
106         Reply to the GET_WORKSPACES message.
107 SUBSCRIBE (2)::
108         Confirmation/Error code for the SUBSCRIBE message.
109 GET_OUTPUTS (3)::
110         Reply to the GET_OUTPUTS message.
111 GET_TREE (4)::
112         Reply to the GET_TREE message.
113
114 === COMMAND reply
115
116 The reply consists of a single serialized map. At the moment, the only
117 property is +success (bool)+, but this will be expanded in future versions.
118
119 *Example:*
120 -------------------
121 { "success": true }
122 -------------------
123
124 === GET_WORKSPACES reply
125
126 The reply consists of a serialized list of workspaces. Each workspace has the
127 following properties:
128
129 num (integer)::
130         The logical number of the workspace. Corresponds to the command
131         to switch to this workspace.
132 name (string)::
133         The name of this workspace (by default num+1), as changed by the
134         user. Encoded in UTF-8.
135 visible (boolean)::
136         Whether this workspace is currently visible on an output (multiple
137         workspaces can be visible at the same time).
138 focused (boolean)::
139         Whether this workspace currently has the focus (only one workspace
140         can have the focus at the same time).
141 urgent (boolean)::
142         Whether a window on this workspace has the "urgent" flag set.
143 rect (map)::
144         The rectangle of this workspace (equals the rect of the output it
145         is on), consists of x, y, width, height.
146 output (string)::
147         The video output this workspace is on (LVDS1, VGA1, …).
148
149 *Example:*
150 -------------------
151 [
152  {
153   "num": 0,
154   "name": "1",
155   "visible": true,
156   "focused": true,
157   "urgent": false,
158   "rect": {
159    "x": 0,
160    "y": 0,
161    "width": 1280,
162    "height": 800
163   },
164   "output": "LVDS1"
165  },
166  {
167   "num": 1,
168   "name": "2",
169   "visible": false,
170   "focused": false,
171   "urgent": false,
172   "rect": {
173    "x": 0,
174    "y": 0,
175    "width": 1280,
176    "height": 800
177   },
178   "output": "LVDS1"
179  }
180 ]
181 -------------------
182
183 === SUBSCRIBE reply
184
185 The reply consists of a single serialized map. The only property is
186 +success (bool)+, indicating whether the subscription was successful (the
187 default) or whether a JSON parse error occurred.
188
189 *Example:*
190 -------------------
191 { "success": true }
192 -------------------
193
194 === GET_OUTPUTS reply
195
196 The reply consists of a serialized list of outputs. Each output has the
197 following properties:
198
199 name (string)::
200         The name of this output (as seen in +xrandr(1)+). Encoded in UTF-8.
201 active (boolean)::
202         Whether this output is currently active (has a valid mode).
203 current_workspace (integer)::
204         The current workspace which is visible on this output. +null+ if the
205         output is not active.
206 rect (map)::
207         The rectangle of this output (equals the rect of the output it
208         is on), consists of x, y, width, height.
209
210 *Example:*
211 -------------------
212 [
213  {
214   "name": "LVDS1",
215   "active": true,
216   "current_workspace": 4,
217   "rect": {
218    "x": 0,
219    "y": 0,
220    "width": 1280,
221    "height": 800
222   }
223  },
224  {
225   "name": "VGA1",
226   "active": true,
227   "current_workspace": 1,
228   "rect": {
229    "x": 1280,
230    "y": 0,
231    "width": 1280,
232    "height": 1024
233   },
234  }
235 ]
236 -------------------
237
238 === GET_TREE reply
239
240 The reply consists of a serialized tree. Each node in the tree (representing
241 one container) has at least the properties listed below. While the nodes might
242 have more properties, please do not use any properties which are not documented
243 here. They are not yet finalized and will probably change!
244
245 id (integer)::
246         The internal ID (actually a C pointer value) of this container. Do not
247         make any assumptions about it. You can use it to (re-)identify and
248         address containers when talking to i3.
249 name (string)::
250         The internal name of this container. For all containers which are part
251         of the tree structure down to the workspace contents, this is set to a
252         nice human-readable name of the container.
253         For all other containers, the content is not defined (yet).
254 border (string)::
255         Can be either "normal", "none" or "1pixel", dependending on the
256         container’s border style.
257 layout (string)::
258         Can be either "default", "stacked", "tabbed", "dockarea" or "output".
259         Other values might be possible in the future, should we add new
260         layouts.
261 orientation (string)::
262         Can be either "none" (for non-split containers), "horizontal" or
263         "vertical".
264 percent (float)::
265         The percentage which this container takes in its parent. A value of
266         +null+ means that the percent property does not make sense for this
267         container, for example for the root container.
268 rect (map)::
269         The absolute display coordinates for this container. Display
270         coordinates means that when you have two 1600x1200 monitors on a single
271         X11 Display (the standard way), the coordinates of the first window on
272         the second monitor are +{ "x": 1600, "y": 0, "width": 1600, "height":
273         1200 }+.
274 window_rect (map)::
275         The coordinates of the *actual client window* inside its container.
276         These coordinates are relative to the container and do not include the
277         window decoration (which is actually rendered on the parent container).
278         So, when using the +default+ layout, you will have a 2 pixel border on
279         each side, making the window_rect +{ "x": 2, "y": 0, "width": 632,
280         "height": 366 }+ (for example).
281 geometry (map)::
282         The original geometry the window specified when i3 mapped it. Used when
283         switching a window to floating mode, for example.
284 urgent (bool)::
285         Whether this container (window or workspace) has the urgency hint set.
286 focused (bool)::
287         Whether this container is currently focused.
288
289 Please note that in the following example, I have left out some keys/values
290 which are not relevant for the type of the node. Otherwise, the example would
291 be by far too long (it already is quite long, despite showing only 1 window and
292 one dock window).
293
294 It is useful to have an overview of the structure before taking a look at the
295 JSON dump:
296
297 * root
298 ** LVDS1
299 *** topdock
300 *** content
301 **** workspace 1
302 ***** window 1
303 *** bottomdock
304 **** dock window 1
305 ** VGA1
306
307 *Example:*
308 -----------------------
309 {
310  "id": 6875648,
311  "name": "root",
312  "rect": {
313    "x": 0,
314    "y": 0,
315    "width": 1280,
316    "height": 800
317  },
318  "nodes": [
319
320    {
321     "id": 6878320,
322     "name": "LVDS1",
323     "layout": "output",
324     "rect": {
325       "x": 0,
326       "y": 0,
327       "width": 1280,
328       "height": 800
329     },
330     "nodes": [
331
332       {
333        "id": 6878784,
334        "name": "topdock",
335        "layout": "dockarea",
336        "orientation": "vertical",
337        "rect": {
338          "x": 0,
339          "y": 0,
340          "width": 1280,
341          "height": 0
342        },
343       },
344
345       {
346        "id": 6879344,
347        "name": "content",
348        "rect": {
349          "x": 0,
350          "y": 0,
351          "width": 1280,
352          "height": 782
353        },
354        "nodes": [
355
356          {
357           "id": 6880464,
358           "name": "1",
359           "orientation": "horizontal",
360           "rect": {
361             "x": 0,
362             "y": 0,
363             "width": 1280,
364             "height": 782
365           },
366           "floating_nodes": [],
367           "nodes": [
368
369             {
370              "id": 6929968,
371              "name": "#aa0000",
372              "border": "normal",
373              "percent": 1,
374              "rect": {
375                "x": 0,
376                "y": 18,
377                "width": 1280,
378                "height": 782
379              }
380             }
381
382           ]
383          }
384
385        ]
386       },
387
388       {
389        "id": 6880208,
390        "name": "bottomdock",
391        "layout": "dockarea",
392        "orientation": "vertical",
393        "rect": {
394          "x": 0,
395          "y": 782,
396          "width": 1280,
397          "height": 18
398        },
399        "nodes": [
400
401          {
402           "id": 6931312,
403           "name": "#00aa00",
404           "percent": 1,
405           "rect": {
406             "x": 0,
407             "y": 782,
408             "width": 1280,
409             "height": 18
410           }
411          }
412
413        ]
414       }
415     ]
416    }
417  ]
418 }
419 ------------------------
420
421
422 == Events
423
424 [[events]]
425
426 To get informed when certain things happen in i3, clients can subscribe to
427 events. Events consist of a name (like "workspace") and an event reply type
428 (like I3_IPC_EVENT_WORKSPACE). The events sent by i3 are in the same format
429 as replies to specific commands. However, the highest bit of the message type
430 is set to 1 to indicate that this is an event reply instead of a normal reply.
431
432 Caveat: As soon as you subscribe to an event, it is not guaranteed any longer
433 that the requests to i3 are processed in order. This means, the following
434 situation can happen: You send a GET_WORKSPACES request but you receive a
435 "workspace" event before receiving the reply to GET_WORKSPACES. If your
436 program does not want to cope which such kinds of race conditions (an
437 event based library may not have a problem here), I suggest you create a
438 separate connection to receive events.
439
440 === Subscribing to events
441
442 By sending a message of type SUBSCRIBE with a JSON-encoded array as payload
443 you can register to an event.
444
445 *Example:*
446 ---------------------------------
447 type: SUBSCRIBE
448 payload: [ "workspace", "focus" ]
449 ---------------------------------
450
451
452 === Available events
453
454 The numbers in parenthesis is the event type (keep in mind that you need to
455 strip the highest bit first).
456
457 workspace (0)::
458         Sent when the user switches to a different workspace, when a new
459         workspace is initialized or when a workspace is removed (because the
460         last client vanished).
461 output (1)::
462         Sent when RandR issues a change notification (of either screens,
463         outputs, CRTCs or output properties).
464
465 *Example:*
466 --------------------------------------------------------------------
467 # the appropriate 4 bytes read from the socket are stored in $input
468
469 # unpack a 32-bit unsigned integer
470 my $message_type = unpack("L", $input);
471
472 # check if the highest bit is 1
473 my $is_event = (($message_type >> 31) == 1);
474
475 # use the other bits
476 my $event_type = ($message_type & 0x7F);
477
478 if ($is_event) {
479   say "Received event of type $event_type";
480 }
481 --------------------------------------------------------------------
482
483 === workspace event
484
485 This event consists of a single serialized map containing a property
486 +change (string)+ which indicates the type of the change ("focus", "init",
487 "empty", "urgent").
488
489 *Example:*
490 ---------------------
491 { "change": "focus" }
492 ---------------------
493
494 === output event
495
496 This event consists of a single serialized map containing a property
497 +change (string)+ which indicates the type of the change (currently only
498 "unspecified").
499
500 *Example:*
501 ---------------------------
502 { "change": "unspecified" }
503 ---------------------------
504
505 == See also
506
507 For some languages, libraries are available (so you don’t have to implement
508 all this on your own). This list names some (if you wrote one, please let me
509 know):
510
511 C::
512         i3 includes a headerfile +i3/ipc.h+ which provides you all constants.
513         However, there is no library yet.
514 Ruby::
515         http://github.com/badboy/i3-ipc
516 Perl::
517         http://search.cpan.org/search?query=AnyEvent::I3
518 Python::
519         http://github.com/thepub/i3ipc