]> git.sur5r.net Git - i3/i3/blob - docs/ipc
Merge branch 'master' into next
[i3/i3] / docs / ipc
1 IPC interface (interprocess communication)
2 ==========================================
3 Michael Stapelberg <michael+i3@stapelberg.de>
4 December 2011
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.XXXXXX/ipc-socket.%p+ where +%u+ is your UNIX username, +%p+ is
15 the PID of i3 and XXXXXX is a string of random characters from the portable
16 filename character set (see mkdtemp(3)). You can get the socketpath from i3 by
17 calling +i3 --get-socketpath+.
18
19 All i3 utilities, like +i3-msg+ and +i3-input+ will read the +I3_SOCKET_PATH+
20 X11 property, stored on the X11 root window.
21
22 == Establishing a connection
23
24 To establish a connection, simply open the IPC socket. The following code
25 snippet illustrates this in Perl:
26
27 -------------------------------------------------------------
28 use IO::Socket::UNIX;
29 chomp(my $path = qx(i3 --get-socketpath));
30 my $sock = IO::Socket::UNIX->new(Peer => $path);
31 -------------------------------------------------------------
32
33 == Sending messages to i3
34
35 To send a message to i3, you have to format in the binary message format which
36 i3 expects. This format specifies a magic string in the beginning to ensure
37 the integrity of messages (to prevent follow-up errors). Following the magic
38 string comes the length of the payload of the message as 32-bit integer, and
39 the type of the message as 32-bit integer (the integers are not converted, so
40 they are in native byte order).
41
42 The magic string currently is "i3-ipc" and will only be changed when a change
43 in the IPC API is done which breaks compatibility (we hope that we don’t need
44 to do that).
45
46 Currently implemented message types are the following:
47
48 COMMAND (0)::
49         The payload of the message is a command for i3 (like the commands you
50         can bind to keys in the configuration file) and will be executed
51         directly after receiving it.
52 GET_WORKSPACES (1)::
53         Gets the current workspaces. The reply will be a JSON-encoded list of
54         workspaces (see the reply section).
55 SUBSCRIBE (2)::
56         Subscribes your connection to certain events. See <<events>> for a
57         description of this message and the concept of events.
58 GET_OUTPUTS (3)::
59         Gets the current outputs. The reply will be a JSON-encoded list of outputs
60         (see the reply section).
61 GET_TREE (4)::
62         Gets the layout tree. i3 uses a tree as data structure which includes
63         every container. The reply will be the JSON-encoded tree (see the reply
64         section).
65 GET_MARKS (5)::
66         Gets a list of marks (identifiers for containers to easily jump to them
67         later). The reply will be a JSON-encoded list of window marks (see
68         reply section).
69 GET_BAR_CONFIG (6)::
70         Gets the configuration (as JSON map) of the workspace bar with the
71         given ID. If no ID is provided, an array with all configured bar IDs is
72         returned instead.
73 GET_LOG_MARKERS (7)::
74         Gets the SHM log markers for the current position, the last wrap, the
75         SHM segment name and segment size. This is necessary for tools like
76         i3-dump-log which want to display the SHM log.
77
78 So, a typical message could look like this:
79 --------------------------------------------------
80 "i3-ipc" <message length> <message type> <payload>
81 --------------------------------------------------
82
83 Or, as a hexdump:
84 ------------------------------------------------------------------------------
85 00000000  69 33 2d 69 70 63 04 00  00 00 00 00 00 00 65 78  |i3-ipc........ex|
86 00000010  69 74 0a                                          |it.|
87 ------------------------------------------------------------------------------
88
89 To generate and send such a message, you could use the following code in Perl:
90 ------------------------------------------------------------
91 sub format_ipc_command {
92     my ($msg) = @_;
93     my $len;
94     # Get the real byte count (vs. amount of characters)
95     { use bytes; $len = length($msg); }
96     return "i3-ipc" . pack("LL", $len, 0) . $msg;
97 }
98
99 $sock->write(format_ipc_command("exit"));
100 ------------------------------------------------------------------------------
101
102 == Receiving replies from i3
103
104 Replies from i3 usually consist of a simple string (the length of the string
105 is the message_length, so you can consider them length-prefixed) which in turn
106 contain the JSON serialization of a data structure. For example, the
107 GET_WORKSPACES message returns an array of workspaces (each workspace is a map
108 with certain attributes).
109
110 === Reply format
111
112 The reply format is identical to the normal message format. There also is
113 the magic string, then the message length, then the message type and the
114 payload.
115
116 The following reply types are implemented:
117
118 COMMAND (0)::
119         Confirmation/Error code for the COMMAND message.
120 WORKSPACES (1)::
121         Reply to the GET_WORKSPACES message.
122 SUBSCRIBE (2)::
123         Confirmation/Error code for the SUBSCRIBE message.
124 OUTPUTS (3)::
125         Reply to the GET_OUTPUTS message.
126 TREE (4)::
127         Reply to the GET_TREE message.
128 MARKS (5)::
129         Reply to the GET_MARKS message.
130 BAR_CONFIG (6)::
131         Reply to the GET_BAR_CONFIG message.
132 LOG_MARKERS (7)::
133         Reply to the GET_LOG_MARKERS message.
134
135 === COMMAND reply
136
137 The reply consists of a single serialized map. At the moment, the only
138 property is +success (bool)+, but this will be expanded in future versions.
139
140 *Example:*
141 -------------------
142 { "success": true }
143 -------------------
144
145 === WORKSPACES reply
146
147 The reply consists of a serialized list of workspaces. Each workspace has the
148 following properties:
149
150 num (integer)::
151         The logical number of the workspace. Corresponds to the command
152         to switch to this workspace.
153 name (string)::
154         The name of this workspace (by default num+1), as changed by the
155         user. Encoded in UTF-8.
156 visible (boolean)::
157         Whether this workspace is currently visible on an output (multiple
158         workspaces can be visible at the same time).
159 focused (boolean)::
160         Whether this workspace currently has the focus (only one workspace
161         can have the focus at the same time).
162 urgent (boolean)::
163         Whether a window on this workspace has the "urgent" flag set.
164 rect (map)::
165         The rectangle of this workspace (equals the rect of the output it
166         is on), consists of x, y, width, height.
167 output (string)::
168         The video output this workspace is on (LVDS1, VGA1, …).
169
170 *Example:*
171 -------------------
172 [
173  {
174   "num": 0,
175   "name": "1",
176   "visible": true,
177   "focused": true,
178   "urgent": false,
179   "rect": {
180    "x": 0,
181    "y": 0,
182    "width": 1280,
183    "height": 800
184   },
185   "output": "LVDS1"
186  },
187  {
188   "num": 1,
189   "name": "2",
190   "visible": false,
191   "focused": false,
192   "urgent": false,
193   "rect": {
194    "x": 0,
195    "y": 0,
196    "width": 1280,
197    "height": 800
198   },
199   "output": "LVDS1"
200  }
201 ]
202 -------------------
203
204 === SUBSCRIBE reply
205
206 The reply consists of a single serialized map. The only property is
207 +success (bool)+, indicating whether the subscription was successful (the
208 default) or whether a JSON parse error occurred.
209
210 *Example:*
211 -------------------
212 { "success": true }
213 -------------------
214
215 === GET_OUTPUTS reply
216
217 The reply consists of a serialized list of outputs. Each output has the
218 following properties:
219
220 name (string)::
221         The name of this output (as seen in +xrandr(1)+). Encoded in UTF-8.
222 active (boolean)::
223         Whether this output is currently active (has a valid mode).
224 current_workspace (integer)::
225         The current workspace which is visible on this output. +null+ if the
226         output is not active.
227 rect (map)::
228         The rectangle of this output (equals the rect of the output it
229         is on), consists of x, y, width, height.
230
231 *Example:*
232 -------------------
233 [
234  {
235   "name": "LVDS1",
236   "active": true,
237   "current_workspace": 4,
238   "rect": {
239    "x": 0,
240    "y": 0,
241    "width": 1280,
242    "height": 800
243   }
244  },
245  {
246   "name": "VGA1",
247   "active": true,
248   "current_workspace": 1,
249   "rect": {
250    "x": 1280,
251    "y": 0,
252    "width": 1280,
253    "height": 1024
254   },
255  }
256 ]
257 -------------------
258
259 === TREE reply
260
261 The reply consists of a serialized tree. Each node in the tree (representing
262 one container) has at least the properties listed below. While the nodes might
263 have more properties, please do not use any properties which are not documented
264 here. They are not yet finalized and will probably change!
265
266 id (integer)::
267         The internal ID (actually a C pointer value) of this container. Do not
268         make any assumptions about it. You can use it to (re-)identify and
269         address containers when talking to i3.
270 name (string)::
271         The internal name of this container. For all containers which are part
272         of the tree structure down to the workspace contents, this is set to a
273         nice human-readable name of the container.
274         For all other containers, the content is not defined (yet).
275 border (string)::
276         Can be either "normal", "none" or "1pixel", dependending on the
277         container’s border style.
278 layout (string)::
279         Can be either "default", "stacked", "tabbed", "dockarea" or "output".
280         Other values might be possible in the future, should we add new
281         layouts.
282 orientation (string)::
283         Can be either "none" (for non-split containers), "horizontal" or
284         "vertical".
285 percent (float)::
286         The percentage which this container takes in its parent. A value of
287         +null+ means that the percent property does not make sense for this
288         container, for example for the root container.
289 rect (map)::
290         The absolute display coordinates for this container. Display
291         coordinates means that when you have two 1600x1200 monitors on a single
292         X11 Display (the standard way), the coordinates of the first window on
293         the second monitor are +{ "x": 1600, "y": 0, "width": 1600, "height":
294         1200 }+.
295 window_rect (map)::
296         The coordinates of the *actual client window* inside its container.
297         These coordinates are relative to the container and do not include the
298         window decoration (which is actually rendered on the parent container).
299         So, when using the +default+ layout, you will have a 2 pixel border on
300         each side, making the window_rect +{ "x": 2, "y": 0, "width": 632,
301         "height": 366 }+ (for example).
302 geometry (map)::
303         The original geometry the window specified when i3 mapped it. Used when
304         switching a window to floating mode, for example.
305 urgent (bool)::
306         Whether this container (window or workspace) has the urgency hint set.
307 focused (bool)::
308         Whether this container is currently focused.
309
310 Please note that in the following example, I have left out some keys/values
311 which are not relevant for the type of the node. Otherwise, the example would
312 be by far too long (it already is quite long, despite showing only 1 window and
313 one dock window).
314
315 It is useful to have an overview of the structure before taking a look at the
316 JSON dump:
317
318 * root
319 ** LVDS1
320 *** topdock
321 *** content
322 **** workspace 1
323 ***** window 1
324 *** bottomdock
325 **** dock window 1
326 ** VGA1
327
328 *Example:*
329 -----------------------
330 {
331  "id": 6875648,
332  "name": "root",
333  "rect": {
334    "x": 0,
335    "y": 0,
336    "width": 1280,
337    "height": 800
338  },
339  "nodes": [
340
341    {
342     "id": 6878320,
343     "name": "LVDS1",
344     "layout": "output",
345     "rect": {
346       "x": 0,
347       "y": 0,
348       "width": 1280,
349       "height": 800
350     },
351     "nodes": [
352
353       {
354        "id": 6878784,
355        "name": "topdock",
356        "layout": "dockarea",
357        "orientation": "vertical",
358        "rect": {
359          "x": 0,
360          "y": 0,
361          "width": 1280,
362          "height": 0
363        },
364       },
365
366       {
367        "id": 6879344,
368        "name": "content",
369        "rect": {
370          "x": 0,
371          "y": 0,
372          "width": 1280,
373          "height": 782
374        },
375        "nodes": [
376
377          {
378           "id": 6880464,
379           "name": "1",
380           "orientation": "horizontal",
381           "rect": {
382             "x": 0,
383             "y": 0,
384             "width": 1280,
385             "height": 782
386           },
387           "floating_nodes": [],
388           "nodes": [
389
390             {
391              "id": 6929968,
392              "name": "#aa0000",
393              "border": "normal",
394              "percent": 1,
395              "rect": {
396                "x": 0,
397                "y": 18,
398                "width": 1280,
399                "height": 782
400              }
401             }
402
403           ]
404          }
405
406        ]
407       },
408
409       {
410        "id": 6880208,
411        "name": "bottomdock",
412        "layout": "dockarea",
413        "orientation": "vertical",
414        "rect": {
415          "x": 0,
416          "y": 782,
417          "width": 1280,
418          "height": 18
419        },
420        "nodes": [
421
422          {
423           "id": 6931312,
424           "name": "#00aa00",
425           "percent": 1,
426           "rect": {
427             "x": 0,
428             "y": 782,
429             "width": 1280,
430             "height": 18
431           }
432          }
433
434        ]
435       }
436     ]
437    }
438  ]
439 }
440 ------------------------
441
442 === MARKS reply
443
444 The reply consists of a single array of strings for each container that has a
445 mark. The order of that array is undefined. If more than one container has the
446 same mark, it will be represented multiple times in the reply (the array
447 contents are not unique).
448
449 If no window has a mark the response will be the empty array [].
450
451 === BAR_CONFIG reply
452
453 This can be used by third-party workspace bars (especially i3bar, but others
454 are free to implement compatible alternatives) to get the +bar+ block
455 configuration from i3.
456
457 Depending on the input, the reply is either:
458
459 empty input::
460         An array of configured bar IDs
461 Bar ID::
462         A JSON map containing the configuration for the specified bar.
463
464 Each bar configuration has the following properties:
465
466 id (string)::
467         The ID for this bar. Included in case you request multiple
468         configurations and want to differentiate the different replies.
469 mode (string)::
470         Either +dock+ (the bar sets the dock window type) or +hide+ (the bar
471         does not show unless a specific key is pressed).
472 position (string)::
473         Either +bottom+ or +top+ at the moment.
474 status_command (string)::
475         Command which will be run to generate a statusline. Each line on stdout
476         of this command will be displayed in the bar. At the moment, no
477         formatting is supported.
478 font (string)::
479         The font to use for text on the bar.
480 workspace_buttons (boolean)::
481         Display workspace buttons or not? Defaults to true.
482 verbose (boolean)::
483         Should the bar enable verbose output for debugging? Defaults to false.
484 colors (map)::
485         Contains key/value pairs of colors. Each value is a color code in hex,
486         formatted #rrggbb (like in HTML).
487
488 The following colors can be configured at the moment:
489
490 background::
491         Background color of the bar.
492 statusline::
493         Text color to be used for the statusline.
494 focused_workspace_text/focused_workspace_bg::
495         Text color/background color for a workspace button when the workspace
496         has focus.
497 active_workspace_text/active_workspace_bg::
498         Text color/background color for a workspace button when the workspace
499         is active (visible) on some output, but the focus is on another one.
500         You can only tell this apart from the focused workspace when you are
501         using multiple monitors.
502 inactive_workspace_text/inactive_workspace_bg::
503         Text color/background color for a workspace button when the workspace
504         does not have focus and is not active (visible) on any output. This
505         will be the case for most workspaces.
506 urgent_workspace_text/urgent_workspace_bar::
507         Text color/background color for workspaces which contain at least one
508         window with the urgency hint set.
509
510
511 *Example of configured bars:*
512 --------------
513 ["bar-bxuqzf"]
514 --------------
515
516 *Example of bar configuration:*
517 --------------
518 {
519  "id": "bar-bxuqzf",
520  "mode": "dock",
521  "position": "bottom",
522  "status_command": "i3status",
523  "font": "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1",
524  "workspace_buttons": true,
525  "verbose": false,
526  "colors": {
527    "background": "#c0c0c0",
528    "statusline": "#00ff00",
529    "focused_workspace_text": "#ffffff",
530    "focused_workspace_bg": "#000000"
531  }
532 }
533 --------------
534
535 === LOG_MARKERS reply
536
537 Gets the SHM log markers for the current position, the last wrap, the
538 SHM segment name and segment size. This is necessary for tools like
539 i3-dump-log which want to display the SHM log.
540
541 The reply is a JSON map with the following entries:
542
543 shmname (string)::
544         The name of the SHM segment, will be of the format +/i3-log-<pid>+.
545 size (integer)::
546         The size (in bytes) of the SHM segment. If this is 0, SHM logging is
547         disabled.
548 offset_next_write (integer)::
549         The offset in the SHM segment at which the next write will happen.
550         Tools should start printing lines from here, since the bytes following
551         this offset are the oldest log lines. However, the first line might be
552         garbled, so it makes sense to skip all bytes until the first \0.
553 offset_last_wrap (integer)::
554         The offset in the SHM segment at which the last wrap occured. i3 only
555         stores entire messages in the SHM log, so it might waste a few bytes at
556         the end to be more efficient. Tools should not print content after the
557         offset_last_wrap.
558
559 *Example*:
560 -----------------------------
561 {
562   "offset_next_write":132839,
563   "offset_last_wrap":26214400,
564   "shmname":"/i3-log-3392",
565   "size":26214400
566 }
567 -----------------------------
568
569 == Events
570
571 [[events]]
572
573 To get informed when certain things happen in i3, clients can subscribe to
574 events. Events consist of a name (like "workspace") and an event reply type
575 (like I3_IPC_EVENT_WORKSPACE). The events sent by i3 are in the same format
576 as replies to specific commands. However, the highest bit of the message type
577 is set to 1 to indicate that this is an event reply instead of a normal reply.
578
579 Caveat: As soon as you subscribe to an event, it is not guaranteed any longer
580 that the requests to i3 are processed in order. This means, the following
581 situation can happen: You send a GET_WORKSPACES request but you receive a
582 "workspace" event before receiving the reply to GET_WORKSPACES. If your
583 program does not want to cope which such kinds of race conditions (an
584 event based library may not have a problem here), I suggest you create a
585 separate connection to receive events.
586
587 === Subscribing to events
588
589 By sending a message of type SUBSCRIBE with a JSON-encoded array as payload
590 you can register to an event.
591
592 *Example:*
593 ---------------------------------
594 type: SUBSCRIBE
595 payload: [ "workspace", "focus" ]
596 ---------------------------------
597
598
599 === Available events
600
601 The numbers in parenthesis is the event type (keep in mind that you need to
602 strip the highest bit first).
603
604 workspace (0)::
605         Sent when the user switches to a different workspace, when a new
606         workspace is initialized or when a workspace is removed (because the
607         last client vanished).
608 output (1)::
609         Sent when RandR issues a change notification (of either screens,
610         outputs, CRTCs or output properties).
611
612 *Example:*
613 --------------------------------------------------------------------
614 # the appropriate 4 bytes read from the socket are stored in $input
615
616 # unpack a 32-bit unsigned integer
617 my $message_type = unpack("L", $input);
618
619 # check if the highest bit is 1
620 my $is_event = (($message_type >> 31) == 1);
621
622 # use the other bits
623 my $event_type = ($message_type & 0x7F);
624
625 if ($is_event) {
626   say "Received event of type $event_type";
627 }
628 --------------------------------------------------------------------
629
630 === workspace event
631
632 This event consists of a single serialized map containing a property
633 +change (string)+ which indicates the type of the change ("focus", "init",
634 "empty", "urgent").
635
636 *Example:*
637 ---------------------
638 { "change": "focus" }
639 ---------------------
640
641 === output event
642
643 This event consists of a single serialized map containing a property
644 +change (string)+ which indicates the type of the change (currently only
645 "unspecified").
646
647 *Example:*
648 ---------------------------
649 { "change": "unspecified" }
650 ---------------------------
651
652 == See also
653
654 For some languages, libraries are available (so you don’t have to implement
655 all this on your own). This list names some (if you wrote one, please let me
656 know):
657
658 C::
659         i3 includes a headerfile +i3/ipc.h+ which provides you all constants.
660         However, there is no library yet.
661 Ruby::
662         http://github.com/badboy/i3-ipc
663 Perl::
664         http://search.cpan.org/search?query=AnyEvent::I3
665 Python::
666         http://github.com/thepub/i3ipc