i3
ipc.c
Go to the documentation of this file.
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
8  *
9  */
10 #include "all.h"
11 
12 #include "yajl_utils.h"
13 
14 #include <stdint.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <libev/ev.h>
20 #include <yajl/yajl_gen.h>
21 #include <yajl/yajl_parse.h>
22 
23 char *current_socketpath = NULL;
24 
25 TAILQ_HEAD(ipc_client_head, ipc_client)
27 
28 /*
29  * Puts the given socket file descriptor into non-blocking mode or dies if
30  * setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our
31  * IPC model because we should by no means block the window manager.
32  *
33  */
34 static void set_nonblock(int sockfd) {
35  int flags = fcntl(sockfd, F_GETFL, 0);
36  if (flags & O_NONBLOCK) {
37  return;
38  }
39  flags |= O_NONBLOCK;
40  if (fcntl(sockfd, F_SETFL, flags) < 0)
41  err(-1, "Could not set O_NONBLOCK");
42 }
43 
44 static void ipc_client_timeout(EV_P_ ev_timer *w, int revents);
45 static void ipc_socket_writeable_cb(EV_P_ struct ev_io *w, int revents);
46 
47 static ev_tstamp kill_timeout = 10.0;
48 
49 void ipc_set_kill_timeout(ev_tstamp new) {
50  kill_timeout = new;
51 }
52 
53 /*
54  * Try to write the contents of the pending buffer to the client's subscription
55  * socket. Will set, reset or clear the timeout and io write callbacks depending
56  * on the result of the write operation.
57  *
58  */
59 static void ipc_push_pending(ipc_client *client) {
60  const ssize_t result = writeall_nonblock(client->fd, client->buffer, client->buffer_size);
61  if (result < 0) {
62  return;
63  }
64 
65  if ((size_t)result == client->buffer_size) {
66  /* Everything was written successfully: clear the timer and stop the io
67  * callback. */
68  FREE(client->buffer);
69  client->buffer_size = 0;
70  if (client->timeout) {
71  ev_timer_stop(main_loop, client->timeout);
72  FREE(client->timeout);
73  }
74  ev_io_stop(main_loop, client->write_callback);
75  return;
76  }
77 
78  /* Otherwise, make sure that the io callback is enabled and create a new
79  * timer if needed. */
80  ev_io_start(main_loop, client->write_callback);
81 
82  if (!client->timeout) {
83  struct ev_timer *timeout = scalloc(1, sizeof(struct ev_timer));
84  ev_timer_init(timeout, ipc_client_timeout, kill_timeout, 0.);
85  timeout->data = client;
86  client->timeout = timeout;
87  ev_set_priority(timeout, EV_MINPRI);
88  ev_timer_start(main_loop, client->timeout);
89  } else if (result > 0) {
90  /* Keep the old timeout when nothing is written. Otherwise, we would
91  * keep a dead connection by continuously renewing its timeouts. */
92  ev_timer_stop(main_loop, client->timeout);
93  ev_timer_set(client->timeout, kill_timeout, 0.0);
94  ev_timer_start(main_loop, client->timeout);
95  }
96  if (result == 0) {
97  return;
98  }
99 
100  /* Shift the buffer to the left and reduce the allocated space. */
101  client->buffer_size -= (size_t)result;
102  memmove(client->buffer, client->buffer + result, client->buffer_size);
103  client->buffer = srealloc(client->buffer, client->buffer_size);
104 }
105 
106 /*
107  * Given a message and a message type, create the corresponding header, merge it
108  * with the message and append it to the given client's output buffer. Also,
109  * send the message if the client's buffer was empty.
110  *
111  */
112 static void ipc_send_client_message(ipc_client *client, size_t size, const uint32_t message_type, const uint8_t *payload) {
113  const i3_ipc_header_t header = {
114  .magic = {'i', '3', '-', 'i', 'p', 'c'},
115  .size = size,
116  .type = message_type};
117  const size_t header_size = sizeof(i3_ipc_header_t);
118  const size_t message_size = header_size + size;
119 
120  const bool push_now = (client->buffer_size == 0);
121  client->buffer = srealloc(client->buffer, client->buffer_size + message_size);
122  memcpy(client->buffer + client->buffer_size, ((void *)&header), header_size);
123  memcpy(client->buffer + client->buffer_size + header_size, payload, size);
124  client->buffer_size += message_size;
125 
126  if (push_now) {
127  ipc_push_pending(client);
128  }
129 }
130 
131 static void free_ipc_client(ipc_client *client, int exempt_fd) {
132  if (client->fd != exempt_fd) {
133  DLOG("Disconnecting client on fd %d\n", client->fd);
134  close(client->fd);
135  }
136 
137  ev_io_stop(main_loop, client->read_callback);
138  FREE(client->read_callback);
139  ev_io_stop(main_loop, client->write_callback);
140  FREE(client->write_callback);
141  if (client->timeout) {
142  ev_timer_stop(main_loop, client->timeout);
143  FREE(client->timeout);
144  }
145 
146  free(client->buffer);
147 
148  for (int i = 0; i < client->num_events; i++) {
149  free(client->events[i]);
150  }
151  free(client->events);
152  TAILQ_REMOVE(&all_clients, client, clients);
153  free(client);
154 }
155 
156 /*
157  * Sends the specified event to all IPC clients which are currently connected
158  * and subscribed to this kind of event.
159  *
160  */
161 void ipc_send_event(const char *event, uint32_t message_type, const char *payload) {
162  ipc_client *current;
163  TAILQ_FOREACH(current, &all_clients, clients) {
164  for (int i = 0; i < current->num_events; i++) {
165  if (strcasecmp(current->events[i], event) == 0) {
166  ipc_send_client_message(current, strlen(payload), message_type, (uint8_t *)payload);
167  break;
168  }
169  }
170  }
171 }
172 
173 /*
174  * For shutdown events, we send the reason for the shutdown.
175  */
177  yajl_gen gen = ygenalloc();
178  y(map_open);
179 
180  ystr("change");
181 
182  if (reason == SHUTDOWN_REASON_RESTART) {
183  ystr("restart");
184  } else if (reason == SHUTDOWN_REASON_EXIT) {
185  ystr("exit");
186  }
187 
188  y(map_close);
189 
190  const unsigned char *payload;
191  ylength length;
192 
193  y(get_buf, &payload, &length);
194  ipc_send_event("shutdown", I3_IPC_EVENT_SHUTDOWN, (const char *)payload);
195 
196  y(free);
197 }
198 
199 /*
200  * Calls shutdown() on each socket and closes it. This function is to be called
201  * when exiting or restarting only!
202  *
203  * exempt_fd is never closed. Set to -1 to close all fds.
204  *
205  */
206 void ipc_shutdown(shutdown_reason_t reason, int exempt_fd) {
207  ipc_send_shutdown_event(reason);
208 
209  ipc_client *current;
210  while (!TAILQ_EMPTY(&all_clients)) {
211  current = TAILQ_FIRST(&all_clients);
212  if (current->fd != exempt_fd) {
213  shutdown(current->fd, SHUT_RDWR);
214  }
215  free_ipc_client(current, exempt_fd);
216  }
217 }
218 
219 /*
220  * Executes the command and returns whether it could be successfully parsed
221  * or not (at the moment, always returns true).
222  *
223  */
224 IPC_HANDLER(run_command) {
225  /* To get a properly terminated buffer, we copy
226  * message_size bytes out of the buffer */
227  char *command = sstrndup((const char *)message, message_size);
228  LOG("IPC: received: *%s*\n", command);
229  yajl_gen gen = yajl_gen_alloc(NULL);
230 
231  CommandResult *result = parse_command(command, gen, client);
232  free(command);
233 
234  if (result->needs_tree_render)
235  tree_render();
236 
237  command_result_free(result);
238 
239  const unsigned char *reply;
240  ylength length;
241  yajl_gen_get_buf(gen, &reply, &length);
242 
243  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_COMMAND,
244  (const uint8_t *)reply);
245 
246  yajl_gen_free(gen);
247 }
248 
249 static void dump_rect(yajl_gen gen, const char *name, Rect r) {
250  ystr(name);
251  y(map_open);
252  ystr("x");
253  y(integer, r.x);
254  ystr("y");
255  y(integer, r.y);
256  ystr("width");
257  y(integer, r.width);
258  ystr("height");
259  y(integer, r.height);
260  y(map_close);
261 }
262 
263 static void dump_gaps(yajl_gen gen, const char *name, gaps_t gaps) {
264  ystr(name);
265  y(map_open);
266  ystr("inner");
267  y(integer, gaps.inner);
268 
269  // TODO: the i3ipc Python modules recognize gaps, but only inner/outer
270  // This is currently here to preserve compatibility with that
271  ystr("outer");
272  y(integer, gaps.top);
273 
274  ystr("top");
275  y(integer, gaps.top);
276  ystr("right");
277  y(integer, gaps.right);
278  ystr("bottom");
279  y(integer, gaps.bottom);
280  ystr("left");
281  y(integer, gaps.left);
282  y(map_close);
283 }
284 
285 static void dump_event_state_mask(yajl_gen gen, Binding *bind) {
286  y(array_open);
287  for (int i = 0; i < 20; i++) {
288  if (bind->event_state_mask & (1 << i)) {
289  switch (1 << i) {
290  case XCB_KEY_BUT_MASK_SHIFT:
291  ystr("shift");
292  break;
293  case XCB_KEY_BUT_MASK_LOCK:
294  ystr("lock");
295  break;
296  case XCB_KEY_BUT_MASK_CONTROL:
297  ystr("ctrl");
298  break;
299  case XCB_KEY_BUT_MASK_MOD_1:
300  ystr("Mod1");
301  break;
302  case XCB_KEY_BUT_MASK_MOD_2:
303  ystr("Mod2");
304  break;
305  case XCB_KEY_BUT_MASK_MOD_3:
306  ystr("Mod3");
307  break;
308  case XCB_KEY_BUT_MASK_MOD_4:
309  ystr("Mod4");
310  break;
311  case XCB_KEY_BUT_MASK_MOD_5:
312  ystr("Mod5");
313  break;
314  case XCB_KEY_BUT_MASK_BUTTON_1:
315  ystr("Button1");
316  break;
317  case XCB_KEY_BUT_MASK_BUTTON_2:
318  ystr("Button2");
319  break;
320  case XCB_KEY_BUT_MASK_BUTTON_3:
321  ystr("Button3");
322  break;
323  case XCB_KEY_BUT_MASK_BUTTON_4:
324  ystr("Button4");
325  break;
326  case XCB_KEY_BUT_MASK_BUTTON_5:
327  ystr("Button5");
328  break;
329  case (I3_XKB_GROUP_MASK_1 << 16):
330  ystr("Group1");
331  break;
332  case (I3_XKB_GROUP_MASK_2 << 16):
333  ystr("Group2");
334  break;
335  case (I3_XKB_GROUP_MASK_3 << 16):
336  ystr("Group3");
337  break;
338  case (I3_XKB_GROUP_MASK_4 << 16):
339  ystr("Group4");
340  break;
341  }
342  }
343  }
344  y(array_close);
345 }
346 
347 static void dump_binding(yajl_gen gen, Binding *bind) {
348  y(map_open);
349  ystr("input_code");
350  y(integer, bind->keycode);
351 
352  ystr("input_type");
353  ystr((const char *)(bind->input_type == B_KEYBOARD ? "keyboard" : "mouse"));
354 
355  ystr("symbol");
356  if (bind->symbol == NULL)
357  y(null);
358  else
359  ystr(bind->symbol);
360 
361  ystr("command");
362  ystr(bind->command);
363 
364  // This key is only provided for compatibility, new programs should use
365  // event_state_mask instead.
366  ystr("mods");
367  dump_event_state_mask(gen, bind);
368 
369  ystr("event_state_mask");
370  dump_event_state_mask(gen, bind);
371 
372  y(map_close);
373 }
374 
375 void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
376  y(map_open);
377  ystr("id");
378  y(integer, (uintptr_t)con);
379 
380  ystr("type");
381  switch (con->type) {
382  case CT_ROOT:
383  ystr("root");
384  break;
385  case CT_OUTPUT:
386  ystr("output");
387  break;
388  case CT_CON:
389  ystr("con");
390  break;
391  case CT_FLOATING_CON:
392  ystr("floating_con");
393  break;
394  case CT_WORKSPACE:
395  ystr("workspace");
396  break;
397  case CT_DOCKAREA:
398  ystr("dockarea");
399  break;
400  }
401 
402  /* provided for backwards compatibility only. */
403  ystr("orientation");
404  if (!con_is_split(con))
405  ystr("none");
406  else {
407  if (con_orientation(con) == HORIZ)
408  ystr("horizontal");
409  else
410  ystr("vertical");
411  }
412 
413  ystr("scratchpad_state");
414  switch (con->scratchpad_state) {
415  case SCRATCHPAD_NONE:
416  ystr("none");
417  break;
418  case SCRATCHPAD_FRESH:
419  ystr("fresh");
420  break;
421  case SCRATCHPAD_CHANGED:
422  ystr("changed");
423  break;
424  }
425 
426  ystr("percent");
427  if (con->percent == 0.0)
428  y(null);
429  else
430  y(double, con->percent);
431 
432  ystr("urgent");
433  y(bool, con->urgent);
434 
435  if (!TAILQ_EMPTY(&(con->marks_head))) {
436  ystr("marks");
437  y(array_open);
438 
439  mark_t *mark;
440  TAILQ_FOREACH(mark, &(con->marks_head), marks) {
441  ystr(mark->name);
442  }
443 
444  y(array_close);
445  }
446 
447  ystr("focused");
448  y(bool, (con == focused));
449 
450  if (con->type != CT_ROOT && con->type != CT_OUTPUT) {
451  ystr("output");
452  ystr(con_get_output(con)->name);
453  }
454 
455  ystr("layout");
456  switch (con->layout) {
457  case L_DEFAULT:
458  DLOG("About to dump layout=default, this is a bug in the code.\n");
459  assert(false);
460  break;
461  case L_SPLITV:
462  ystr("splitv");
463  break;
464  case L_SPLITH:
465  ystr("splith");
466  break;
467  case L_STACKED:
468  ystr("stacked");
469  break;
470  case L_TABBED:
471  ystr("tabbed");
472  break;
473  case L_DOCKAREA:
474  ystr("dockarea");
475  break;
476  case L_OUTPUT:
477  ystr("output");
478  break;
479  }
480 
481  ystr("workspace_layout");
482  switch (con->workspace_layout) {
483  case L_DEFAULT:
484  ystr("default");
485  break;
486  case L_STACKED:
487  ystr("stacked");
488  break;
489  case L_TABBED:
490  ystr("tabbed");
491  break;
492  default:
493  DLOG("About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
494  assert(false);
495  break;
496  }
497 
498  ystr("last_split_layout");
499  switch (con->layout) {
500  case L_SPLITV:
501  ystr("splitv");
502  break;
503  default:
504  ystr("splith");
505  break;
506  }
507 
508  ystr("border");
509  switch (con->border_style) {
510  case BS_NORMAL:
511  ystr("normal");
512  break;
513  case BS_NONE:
514  ystr("none");
515  break;
516  case BS_PIXEL:
517  ystr("pixel");
518  break;
519  }
520 
521  ystr("current_border_width");
522  y(integer, con->current_border_width);
523 
524  dump_rect(gen, "rect", con->rect);
525  dump_rect(gen, "deco_rect", con->deco_rect);
526  dump_rect(gen, "window_rect", con->window_rect);
527  dump_rect(gen, "geometry", con->geometry);
528 
529  ystr("name");
530  if (con->window && con->window->name)
531  ystr(i3string_as_utf8(con->window->name));
532  else if (con->name != NULL)
533  ystr(con->name);
534  else
535  y(null);
536 
537  if (con->title_format != NULL) {
538  ystr("title_format");
539  ystr(con->title_format);
540  }
541 
542  if (con->type == CT_WORKSPACE) {
543  ystr("num");
544  y(integer, con->num);
545 
546  dump_gaps(gen, "gaps", con->gaps);
547  }
548 
549  ystr("window");
550  if (con->window)
551  y(integer, con->window->id);
552  else
553  y(null);
554 
555  ystr("window_type");
556  if (con->window) {
557  if (con->window->window_type == A__NET_WM_WINDOW_TYPE_NORMAL) {
558  ystr("normal");
559  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DOCK) {
560  ystr("dock");
561  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DIALOG) {
562  ystr("dialog");
563  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_UTILITY) {
564  ystr("utility");
565  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_TOOLBAR) {
566  ystr("toolbar");
567  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_SPLASH) {
568  ystr("splash");
569  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_MENU) {
570  ystr("menu");
571  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) {
572  ystr("dropdown_menu");
573  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_POPUP_MENU) {
574  ystr("popup_menu");
575  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_TOOLTIP) {
576  ystr("tooltip");
577  } else if (con->window->window_type == A__NET_WM_WINDOW_TYPE_NOTIFICATION) {
578  ystr("notification");
579  } else {
580  ystr("unknown");
581  }
582  } else
583  y(null);
584 
585  if (con->window && !inplace_restart) {
586  /* Window properties are useless to preserve when restarting because
587  * they will be queried again anyway. However, for i3-save-tree(1),
588  * they are very useful and save i3-save-tree dealing with X11. */
589  ystr("window_properties");
590  y(map_open);
591 
592 #define DUMP_PROPERTY(key, prop_name) \
593  do { \
594  if (con->window->prop_name != NULL) { \
595  ystr(key); \
596  ystr(con->window->prop_name); \
597  } \
598  } while (0)
599 
600  DUMP_PROPERTY("class", class_class);
601  DUMP_PROPERTY("instance", class_instance);
602  DUMP_PROPERTY("window_role", role);
603 
604  if (con->window->name != NULL) {
605  ystr("title");
606  ystr(i3string_as_utf8(con->window->name));
607  }
608 
609  ystr("transient_for");
610  if (con->window->transient_for == XCB_NONE)
611  y(null);
612  else
613  y(integer, con->window->transient_for);
614 
615  y(map_close);
616  }
617 
618  ystr("nodes");
619  y(array_open);
620  Con *node;
621  if (con->type != CT_DOCKAREA || !inplace_restart) {
622  TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
623  dump_node(gen, node, inplace_restart);
624  }
625  }
626  y(array_close);
627 
628  ystr("floating_nodes");
629  y(array_open);
630  TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
631  dump_node(gen, node, inplace_restart);
632  }
633  y(array_close);
634 
635  ystr("focus");
636  y(array_open);
637  TAILQ_FOREACH(node, &(con->focus_head), focused) {
638  y(integer, (uintptr_t)node);
639  }
640  y(array_close);
641 
642  ystr("fullscreen_mode");
643  y(integer, con->fullscreen_mode);
644 
645  ystr("sticky");
646  y(bool, con->sticky);
647 
648  ystr("floating");
649  switch (con->floating) {
650  case FLOATING_AUTO_OFF:
651  ystr("auto_off");
652  break;
653  case FLOATING_AUTO_ON:
654  ystr("auto_on");
655  break;
656  case FLOATING_USER_OFF:
657  ystr("user_off");
658  break;
659  case FLOATING_USER_ON:
660  ystr("user_on");
661  break;
662  }
663 
664  ystr("swallows");
665  y(array_open);
666  Match *match;
667  TAILQ_FOREACH(match, &(con->swallow_head), matches) {
668  /* We will generate a new restart_mode match specification after this
669  * loop, so skip this one. */
670  if (match->restart_mode)
671  continue;
672  y(map_open);
673  if (match->dock != M_DONTCHECK) {
674  ystr("dock");
675  y(integer, match->dock);
676  ystr("insert_where");
677  y(integer, match->insert_where);
678  }
679 
680 #define DUMP_REGEX(re_name) \
681  do { \
682  if (match->re_name != NULL) { \
683  ystr(#re_name); \
684  ystr(match->re_name->pattern); \
685  } \
686  } while (0)
687 
688  DUMP_REGEX(class);
689  DUMP_REGEX(instance);
690  DUMP_REGEX(window_role);
691  DUMP_REGEX(title);
692 
693 #undef DUMP_REGEX
694  y(map_close);
695  }
696 
697  if (inplace_restart) {
698  if (con->window != NULL) {
699  y(map_open);
700  ystr("id");
701  y(integer, con->window->id);
702  ystr("restart_mode");
703  y(bool, true);
704  y(map_close);
705  }
706  }
707  y(array_close);
708 
709  if (inplace_restart && con->window != NULL) {
710  ystr("depth");
711  y(integer, con->depth);
712  }
713 
714  if (inplace_restart && con->type == CT_ROOT && previous_workspace_name) {
715  ystr("previous_workspace_name");
717  }
718 
719  y(map_close);
720 }
721 
722 static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
723  if (TAILQ_EMPTY(&(config->bar_bindings)))
724  return;
725 
726  ystr("bindings");
727  y(array_open);
728 
729  struct Barbinding *current;
730  TAILQ_FOREACH(current, &(config->bar_bindings), bindings) {
731  y(map_open);
732 
733  ystr("input_code");
734  y(integer, current->input_code);
735  ystr("command");
736  ystr(current->command);
737  ystr("release");
738  y(bool, current->release == B_UPON_KEYRELEASE);
739 
740  y(map_close);
741  }
742 
743  y(array_close);
744 }
745 
746 static char *canonicalize_output_name(char *name) {
747  /* Do not canonicalize special output names. */
748  if (strcasecmp(name, "primary") == 0) {
749  return name;
750  }
751  Output *output = get_output_by_name(name, false);
752  return output ? output_primary_name(output) : name;
753 }
754 
755 static void dump_bar_config(yajl_gen gen, Barconfig *config) {
756  y(map_open);
757 
758  ystr("id");
759  ystr(config->id);
760 
761  if (config->num_outputs > 0) {
762  ystr("outputs");
763  y(array_open);
764  for (int c = 0; c < config->num_outputs; c++) {
765  /* Convert monitor names (RandR ≥ 1.5) or output names
766  * (RandR < 1.5) into monitor names. This way, existing
767  * configs which use output names transparently keep
768  * working. */
769  ystr(canonicalize_output_name(config->outputs[c]));
770  }
771  y(array_close);
772  }
773 
774  if (!TAILQ_EMPTY(&(config->tray_outputs))) {
775  ystr("tray_outputs");
776  y(array_open);
777 
778  struct tray_output_t *tray_output;
779  TAILQ_FOREACH(tray_output, &(config->tray_outputs), tray_outputs) {
780  ystr(canonicalize_output_name(tray_output->output));
781  }
782 
783  y(array_close);
784  }
785 
786 #define YSTR_IF_SET(name) \
787  do { \
788  if (config->name) { \
789  ystr(#name); \
790  ystr(config->name); \
791  } \
792  } while (0)
793 
794  ystr("tray_padding");
795  y(integer, config->tray_padding);
796 
797  YSTR_IF_SET(socket_path);
798 
799  ystr("mode");
800  switch (config->mode) {
801  case M_HIDE:
802  ystr("hide");
803  break;
804  case M_INVISIBLE:
805  ystr("invisible");
806  break;
807  case M_DOCK:
808  default:
809  ystr("dock");
810  break;
811  }
812 
813  ystr("hidden_state");
814  switch (config->hidden_state) {
815  case S_SHOW:
816  ystr("show");
817  break;
818  case S_HIDE:
819  default:
820  ystr("hide");
821  break;
822  }
823 
824  ystr("modifier");
825  y(integer, config->modifier);
826 
828 
829  ystr("position");
830  if (config->position == P_BOTTOM)
831  ystr("bottom");
832  else
833  ystr("top");
834 
835  YSTR_IF_SET(status_command);
836  YSTR_IF_SET(font);
837 
838  if (config->bar_height) {
839  ystr("bar_height");
840  y(integer, config->bar_height);
841  }
842 
843  if (config->separator_symbol) {
844  ystr("separator_symbol");
845  ystr(config->separator_symbol);
846  }
847 
848  ystr("workspace_buttons");
849  y(bool, !config->hide_workspace_buttons);
850 
851  ystr("workspace_min_width");
852  y(integer, config->workspace_min_width);
853 
854  ystr("strip_workspace_numbers");
855  y(bool, config->strip_workspace_numbers);
856 
857  ystr("strip_workspace_name");
858  y(bool, config->strip_workspace_name);
859 
860  ystr("binding_mode_indicator");
861  y(bool, !config->hide_binding_mode_indicator);
862 
863  ystr("verbose");
864  y(bool, config->verbose);
865 
866 #undef YSTR_IF_SET
867 #define YSTR_IF_SET(name) \
868  do { \
869  if (config->colors.name) { \
870  ystr(#name); \
871  ystr(config->colors.name); \
872  } \
873  } while (0)
874 
875  ystr("colors");
876  y(map_open);
877  YSTR_IF_SET(background);
878  YSTR_IF_SET(statusline);
879  YSTR_IF_SET(separator);
880  YSTR_IF_SET(focused_background);
881  YSTR_IF_SET(focused_statusline);
882  YSTR_IF_SET(focused_separator);
883  YSTR_IF_SET(focused_workspace_border);
884  YSTR_IF_SET(focused_workspace_bg);
885  YSTR_IF_SET(focused_workspace_text);
886  YSTR_IF_SET(active_workspace_border);
887  YSTR_IF_SET(active_workspace_bg);
888  YSTR_IF_SET(active_workspace_text);
889  YSTR_IF_SET(inactive_workspace_border);
890  YSTR_IF_SET(inactive_workspace_bg);
891  YSTR_IF_SET(inactive_workspace_text);
892  YSTR_IF_SET(urgent_workspace_border);
893  YSTR_IF_SET(urgent_workspace_bg);
894  YSTR_IF_SET(urgent_workspace_text);
895  YSTR_IF_SET(binding_mode_border);
896  YSTR_IF_SET(binding_mode_bg);
897  YSTR_IF_SET(binding_mode_text);
898  y(map_close);
899 
900  y(map_close);
901 #undef YSTR_IF_SET
902 }
903 
904 IPC_HANDLER(tree) {
905  setlocale(LC_NUMERIC, "C");
906  yajl_gen gen = ygenalloc();
907  dump_node(gen, croot, false);
908  setlocale(LC_NUMERIC, "");
909 
910  const unsigned char *payload;
911  ylength length;
912  y(get_buf, &payload, &length);
913 
914  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_TREE, payload);
915  y(free);
916 }
917 
918 /*
919  * Formats the reply message for a GET_WORKSPACES request and sends it to the
920  * client
921  *
922  */
923 IPC_HANDLER(get_workspaces) {
924  yajl_gen gen = ygenalloc();
925  y(array_open);
926 
927  Con *focused_ws = con_get_workspace(focused);
928 
929  Con *output;
930  TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
931  if (con_is_internal(output))
932  continue;
933  Con *ws;
934  TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
935  assert(ws->type == CT_WORKSPACE);
936  y(map_open);
937 
938  ystr("id");
939  y(integer, (uintptr_t)ws);
940 
941  ystr("num");
942  y(integer, ws->num);
943 
944  ystr("name");
945  ystr(ws->name);
946 
947  ystr("visible");
948  y(bool, workspace_is_visible(ws));
949 
950  ystr("focused");
951  y(bool, ws == focused_ws);
952 
953  ystr("rect");
954  y(map_open);
955  ystr("x");
956  y(integer, ws->rect.x);
957  ystr("y");
958  y(integer, ws->rect.y);
959  ystr("width");
960  y(integer, ws->rect.width);
961  ystr("height");
962  y(integer, ws->rect.height);
963  y(map_close);
964 
965  ystr("output");
966  ystr(output->name);
967 
968  ystr("urgent");
969  y(bool, ws->urgent);
970 
971  y(map_close);
972  }
973  }
974 
975  y(array_close);
976 
977  const unsigned char *payload;
978  ylength length;
979  y(get_buf, &payload, &length);
980 
981  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
982  y(free);
983 }
984 
985 /*
986  * Formats the reply message for a GET_OUTPUTS request and sends it to the
987  * client
988  *
989  */
990 IPC_HANDLER(get_outputs) {
991  yajl_gen gen = ygenalloc();
992  y(array_open);
993 
994  Output *output;
996  y(map_open);
997 
998  ystr("name");
1000 
1001  ystr("active");
1002  y(bool, output->active);
1003 
1004  ystr("primary");
1005  y(bool, output->primary);
1006 
1007  ystr("rect");
1008  y(map_open);
1009  ystr("x");
1010  y(integer, output->rect.x);
1011  ystr("y");
1012  y(integer, output->rect.y);
1013  ystr("width");
1014  y(integer, output->rect.width);
1015  ystr("height");
1016  y(integer, output->rect.height);
1017  y(map_close);
1018 
1019  ystr("current_workspace");
1020  Con *ws = NULL;
1021  if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
1022  ystr(ws->name);
1023  else
1024  y(null);
1025 
1026  y(map_close);
1027  }
1028 
1029  y(array_close);
1030 
1031  const unsigned char *payload;
1032  ylength length;
1033  y(get_buf, &payload, &length);
1034 
1035  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
1036  y(free);
1037 }
1038 
1039 /*
1040  * Formats the reply message for a GET_MARKS request and sends it to the
1041  * client
1042  *
1043  */
1044 IPC_HANDLER(get_marks) {
1045  yajl_gen gen = ygenalloc();
1046  y(array_open);
1047 
1048  Con *con;
1049  TAILQ_FOREACH(con, &all_cons, all_cons) {
1050  mark_t *mark;
1051  TAILQ_FOREACH(mark, &(con->marks_head), marks) {
1052  ystr(mark->name);
1053  }
1054  }
1055 
1056  y(array_close);
1057 
1058  const unsigned char *payload;
1059  ylength length;
1060  y(get_buf, &payload, &length);
1061 
1062  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_MARKS, payload);
1063  y(free);
1064 }
1065 
1066 /*
1067  * Returns the version of i3
1068  *
1069  */
1070 IPC_HANDLER(get_version) {
1071  yajl_gen gen = ygenalloc();
1072  y(map_open);
1073 
1074  ystr("major");
1075  y(integer, MAJOR_VERSION);
1076 
1077  ystr("minor");
1078  y(integer, MINOR_VERSION);
1079 
1080  ystr("patch");
1081  y(integer, PATCH_VERSION);
1082 
1083  ystr("human_readable");
1084  ystr(i3_version);
1085 
1086  ystr("loaded_config_file_name");
1088 
1089  y(map_close);
1090 
1091  const unsigned char *payload;
1092  ylength length;
1093  y(get_buf, &payload, &length);
1094 
1095  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_VERSION, payload);
1096  y(free);
1097 }
1098 
1099 /*
1100  * Formats the reply message for a GET_BAR_CONFIG request and sends it to the
1101  * client.
1102  *
1103  */
1104 IPC_HANDLER(get_bar_config) {
1105  yajl_gen gen = ygenalloc();
1106 
1107  /* If no ID was passed, we return a JSON array with all IDs */
1108  if (message_size == 0) {
1109  y(array_open);
1110  Barconfig *current;
1111  TAILQ_FOREACH(current, &barconfigs, configs) {
1112  ystr(current->id);
1113  }
1114  y(array_close);
1115 
1116  const unsigned char *payload;
1117  ylength length;
1118  y(get_buf, &payload, &length);
1119 
1120  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
1121  y(free);
1122  return;
1123  }
1124 
1125  /* To get a properly terminated buffer, we copy
1126  * message_size bytes out of the buffer */
1127  char *bar_id = NULL;
1128  sasprintf(&bar_id, "%.*s", message_size, message);
1129  LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id);
1130  Barconfig *current, *config = NULL;
1131  TAILQ_FOREACH(current, &barconfigs, configs) {
1132  if (strcmp(current->id, bar_id) != 0)
1133  continue;
1134 
1135  config = current;
1136  break;
1137  }
1138  free(bar_id);
1139 
1140  if (!config) {
1141  /* If we did not find a config for the given ID, the reply will contain
1142  * a null 'id' field. */
1143  y(map_open);
1144 
1145  ystr("id");
1146  y(null);
1147 
1148  y(map_close);
1149  } else {
1150  dump_bar_config(gen, config);
1151  }
1152 
1153  const unsigned char *payload;
1154  ylength length;
1155  y(get_buf, &payload, &length);
1156 
1157  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
1158  y(free);
1159 }
1160 
1161 /*
1162  * Returns a list of configured binding modes
1163  *
1164  */
1165 IPC_HANDLER(get_binding_modes) {
1166  yajl_gen gen = ygenalloc();
1167 
1168  y(array_open);
1169  struct Mode *mode;
1170  SLIST_FOREACH(mode, &modes, modes) {
1171  ystr(mode->name);
1172  }
1173  y(array_close);
1174 
1175  const unsigned char *payload;
1176  ylength length;
1177  y(get_buf, &payload, &length);
1178 
1179  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BINDING_MODES, payload);
1180  y(free);
1181 }
1182 
1183 /*
1184  * Callback for the YAJL parser (will be called when a string is parsed).
1185  *
1186  */
1187 static int add_subscription(void *extra, const unsigned char *s,
1188  ylength len) {
1189  ipc_client *client = extra;
1190 
1191  DLOG("should add subscription to extra %p, sub %.*s\n", client, (int)len, s);
1192  int event = client->num_events;
1193 
1194  client->num_events++;
1195  client->events = srealloc(client->events, client->num_events * sizeof(char *));
1196  /* We copy the string because it is not null-terminated and strndup()
1197  * is missing on some BSD systems */
1198  client->events[event] = scalloc(len + 1, 1);
1199  memcpy(client->events[event], s, len);
1200 
1201  DLOG("client is now subscribed to:\n");
1202  for (int i = 0; i < client->num_events; i++) {
1203  DLOG("event %s\n", client->events[i]);
1204  }
1205  DLOG("(done)\n");
1206 
1207  return 1;
1208 }
1209 
1210 /*
1211  * Subscribes this connection to the event types which were given as a JSON
1212  * serialized array in the payload field of the message.
1213  *
1214  */
1215 IPC_HANDLER(subscribe) {
1216  yajl_handle p;
1217  yajl_status stat;
1218 
1219  /* Setup the JSON parser */
1220  static yajl_callbacks callbacks = {
1221  .yajl_string = add_subscription,
1222  };
1223 
1224  p = yalloc(&callbacks, (void *)client);
1225  stat = yajl_parse(p, (const unsigned char *)message, message_size);
1226  if (stat != yajl_status_ok) {
1227  unsigned char *err;
1228  err = yajl_get_error(p, true, (const unsigned char *)message,
1229  message_size);
1230  ELOG("YAJL parse error: %s\n", err);
1231  yajl_free_error(p, err);
1232 
1233  const char *reply = "{\"success\":false}";
1234  ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
1235  yajl_free(p);
1236  return;
1237  }
1238  yajl_free(p);
1239  const char *reply = "{\"success\":true}";
1240  ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
1241 
1242  if (client->first_tick_sent) {
1243  return;
1244  }
1245 
1246  bool is_tick = false;
1247  for (int i = 0; i < client->num_events; i++) {
1248  if (strcmp(client->events[i], "tick") == 0) {
1249  is_tick = true;
1250  break;
1251  }
1252  }
1253  if (!is_tick) {
1254  return;
1255  }
1256 
1257  client->first_tick_sent = true;
1258  const char *payload = "{\"first\":true,\"payload\":\"\"}";
1259  ipc_send_client_message(client, strlen(payload), I3_IPC_EVENT_TICK, (const uint8_t *)payload);
1260 }
1261 
1262 /*
1263  * Returns the raw last loaded i3 configuration file contents.
1264  */
1265 IPC_HANDLER(get_config) {
1266  yajl_gen gen = ygenalloc();
1267 
1268  y(map_open);
1269 
1270  ystr("config");
1272 
1273  y(map_close);
1274 
1275  const unsigned char *payload;
1276  ylength length;
1277  y(get_buf, &payload, &length);
1278 
1279  ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_CONFIG, payload);
1280  y(free);
1281 }
1282 
1283 /*
1284  * Sends the tick event from the message payload to subscribers. Establishes a
1285  * synchronization point in event-related tests.
1286  */
1287 IPC_HANDLER(send_tick) {
1288  yajl_gen gen = ygenalloc();
1289 
1290  y(map_open);
1291 
1292  ystr("first");
1293  y(bool, false);
1294 
1295  ystr("payload");
1296  yajl_gen_string(gen, (unsigned char *)message, message_size);
1297 
1298  y(map_close);
1299 
1300  const unsigned char *payload;
1301  ylength length;
1302  y(get_buf, &payload, &length);
1303 
1304  ipc_send_event("tick", I3_IPC_EVENT_TICK, (const char *)payload);
1305  y(free);
1306 
1307  const char *reply = "{\"success\":true}";
1308  ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (const uint8_t *)reply);
1309  DLOG("Sent tick event\n");
1310 }
1311 
1312 struct sync_state {
1313  char *last_key;
1314  uint32_t rnd;
1315  xcb_window_t window;
1316 };
1317 
1318 static int _sync_json_key(void *extra, const unsigned char *val, size_t len) {
1319  struct sync_state *state = extra;
1320  FREE(state->last_key);
1321  state->last_key = scalloc(len + 1, 1);
1322  memcpy(state->last_key, val, len);
1323  return 1;
1324 }
1325 
1326 static int _sync_json_int(void *extra, long long val) {
1327  struct sync_state *state = extra;
1328  if (strcasecmp(state->last_key, "rnd") == 0) {
1329  state->rnd = val;
1330  } else if (strcasecmp(state->last_key, "window") == 0) {
1331  state->window = (xcb_window_t)val;
1332  }
1333  return 1;
1334 }
1335 
1337  yajl_handle p;
1338  yajl_status stat;
1339 
1340  /* Setup the JSON parser */
1341  static yajl_callbacks callbacks = {
1342  .yajl_map_key = _sync_json_key,
1343  .yajl_integer = _sync_json_int,
1344  };
1345 
1346  struct sync_state state;
1347  memset(&state, '\0', sizeof(struct sync_state));
1348  p = yalloc(&callbacks, (void *)&state);
1349  stat = yajl_parse(p, (const unsigned char *)message, message_size);
1350  FREE(state.last_key);
1351  if (stat != yajl_status_ok) {
1352  unsigned char *err;
1353  err = yajl_get_error(p, true, (const unsigned char *)message,
1354  message_size);
1355  ELOG("YAJL parse error: %s\n", err);
1356  yajl_free_error(p, err);
1357 
1358  const char *reply = "{\"success\":false}";
1359  ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
1360  yajl_free(p);
1361  return;
1362  }
1363  yajl_free(p);
1364 
1365  DLOG("received IPC sync request (rnd = %d, window = 0x%08x)\n", state.rnd, state.window);
1366  sync_respond(state.window, state.rnd);
1367  const char *reply = "{\"success\":true}";
1368  ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
1369 }
1370 
1371 /* The index of each callback function corresponds to the numeric
1372  * value of the message type (see include/i3/ipc.h) */
1374  handle_run_command,
1375  handle_get_workspaces,
1376  handle_subscribe,
1377  handle_get_outputs,
1378  handle_tree,
1379  handle_get_marks,
1380  handle_get_bar_config,
1381  handle_get_version,
1382  handle_get_binding_modes,
1383  handle_get_config,
1384  handle_send_tick,
1385  handle_sync,
1386 };
1387 
1388 /*
1389  * Handler for activity on a client connection, receives a message from a
1390  * client.
1391  *
1392  * For now, the maximum message size is 2048. I’m not sure for what the
1393  * IPC interface will be used in the future, thus I’m not implementing a
1394  * mechanism for arbitrarily long messages, as it seems like overkill
1395  * at the moment.
1396  *
1397  */
1398 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
1399  uint32_t message_type;
1400  uint32_t message_length;
1401  uint8_t *message = NULL;
1402  ipc_client *client = (ipc_client *)w->data;
1403  assert(client->fd == w->fd);
1404 
1405  int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message);
1406  /* EOF or other error */
1407  if (ret < 0) {
1408  /* Was this a spurious read? See ev(3) */
1409  if (ret == -1 && errno == EAGAIN) {
1410  FREE(message);
1411  return;
1412  }
1413 
1414  /* If not, there was some kind of error. We don’t bother and close the
1415  * connection. Delete the client from the list of clients. */
1416  free_ipc_client(client, -1);
1417  FREE(message);
1418  return;
1419  }
1420 
1421  if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
1422  DLOG("Unhandled message type: %d\n", message_type);
1423  else {
1424  handler_t h = handlers[message_type];
1425  h(client, message, 0, message_length, message_type);
1426  }
1427 
1428  FREE(message);
1429 }
1430 
1431 static void ipc_client_timeout(EV_P_ ev_timer *w, int revents) {
1432  /* No need to be polite and check for writeability, the other callback would
1433  * have been called by now. */
1434  ipc_client *client = (ipc_client *)w->data;
1435 
1436  char *cmdline = NULL;
1437 #if defined(__linux__) && defined(SO_PEERCRED)
1438  struct ucred peercred;
1439  socklen_t so_len = sizeof(peercred);
1440  if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0) {
1441  goto end;
1442  }
1443  char *exepath;
1444  sasprintf(&exepath, "/proc/%d/cmdline", peercred.pid);
1445 
1446  int fd = open(exepath, O_RDONLY);
1447  free(exepath);
1448  if (fd == -1) {
1449  goto end;
1450  }
1451  char buf[512] = {'\0'}; /* cut off cmdline for the error message. */
1452  const ssize_t n = read(fd, buf, sizeof(buf));
1453  close(fd);
1454  if (n < 0) {
1455  goto end;
1456  }
1457  for (char *walk = buf; walk < buf + n - 1; walk++) {
1458  if (*walk == '\0') {
1459  *walk = ' ';
1460  }
1461  }
1462  cmdline = buf;
1463 
1464  if (cmdline) {
1465  ELOG("client %p with pid %d and cmdline '%s' on fd %d timed out, killing\n", client, peercred.pid, cmdline, client->fd);
1466  }
1467 
1468 end:
1469 #endif
1470  if (!cmdline) {
1471  ELOG("client %p on fd %d timed out, killing\n", client, client->fd);
1472  }
1473 
1474  free_ipc_client(client, -1);
1475 }
1476 
1477 static void ipc_socket_writeable_cb(EV_P_ ev_io *w, int revents) {
1478  DLOG("fd %d writeable\n", w->fd);
1479  ipc_client *client = (ipc_client *)w->data;
1480 
1481  /* If this callback is called then there should be a corresponding active
1482  * timer. */
1483  assert(client->timeout != NULL);
1484  ipc_push_pending(client);
1485 }
1486 
1487 /*
1488  * Handler for activity on the listening socket, meaning that a new client
1489  * has just connected and we should accept() him. Sets up the event handler
1490  * for activity on the new connection and inserts the file descriptor into
1491  * the list of clients.
1492  *
1493  */
1494 void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
1495  struct sockaddr_un peer;
1496  socklen_t len = sizeof(struct sockaddr_un);
1497  int fd;
1498  if ((fd = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) {
1499  if (errno != EINTR) {
1500  perror("accept()");
1501  }
1502  return;
1503  }
1504 
1505  /* Close this file descriptor on exec() */
1506  (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
1507 
1508  ipc_new_client_on_fd(EV_A_ fd);
1509 }
1510 
1511 /*
1512  * ipc_new_client_on_fd() only sets up the event handler
1513  * for activity on the new connection and inserts the file descriptor into
1514  * the list of clients.
1515  *
1516  * This variant is useful for the inherited IPC connection when restarting.
1517  *
1518  */
1520  set_nonblock(fd);
1521 
1522  ipc_client *client = scalloc(1, sizeof(ipc_client));
1523  client->fd = fd;
1524 
1525  client->read_callback = scalloc(1, sizeof(struct ev_io));
1526  client->read_callback->data = client;
1527  ev_io_init(client->read_callback, ipc_receive_message, fd, EV_READ);
1528  ev_io_start(EV_A_ client->read_callback);
1529 
1530  client->write_callback = scalloc(1, sizeof(struct ev_io));
1531  client->write_callback->data = client;
1532  ev_io_init(client->write_callback, ipc_socket_writeable_cb, fd, EV_WRITE);
1533 
1534  DLOG("IPC: new client connected on fd %d\n", fd);
1535  TAILQ_INSERT_TAIL(&all_clients, client, clients);
1536  return client;
1537 }
1538 
1539 /*
1540  * Creates the UNIX domain socket at the given path, sets it to non-blocking
1541  * mode, bind()s and listen()s on it.
1542  *
1543  */
1544 int ipc_create_socket(const char *filename) {
1545  int sockfd;
1546 
1548 
1549  char *resolved = resolve_tilde(filename);
1550  DLOG("Creating IPC-socket at %s\n", resolved);
1551  char *copy = sstrdup(resolved);
1552  const char *dir = dirname(copy);
1553  if (!path_exists(dir))
1554  mkdirp(dir, DEFAULT_DIR_MODE);
1555  free(copy);
1556 
1557  /* Unlink the unix domain socket before */
1558  unlink(resolved);
1559 
1560  if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
1561  perror("socket()");
1562  free(resolved);
1563  return -1;
1564  }
1565 
1566  (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
1567 
1568  struct sockaddr_un addr;
1569  memset(&addr, 0, sizeof(struct sockaddr_un));
1570  addr.sun_family = AF_LOCAL;
1571  strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1);
1572  if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
1573  perror("bind()");
1574  free(resolved);
1575  return -1;
1576  }
1577 
1578  set_nonblock(sockfd);
1579 
1580  if (listen(sockfd, 5) < 0) {
1581  perror("listen()");
1582  free(resolved);
1583  return -1;
1584  }
1585 
1586  current_socketpath = resolved;
1587  return sockfd;
1588 }
1589 
1590 /*
1591  * Generates a json workspace event. Returns a dynamically allocated yajl
1592  * generator. Free with yajl_gen_free().
1593  */
1594 yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) {
1595  setlocale(LC_NUMERIC, "C");
1596  yajl_gen gen = ygenalloc();
1597 
1598  y(map_open);
1599 
1600  ystr("change");
1601  ystr(change);
1602 
1603  ystr("current");
1604  if (current == NULL)
1605  y(null);
1606  else
1607  dump_node(gen, current, false);
1608 
1609  ystr("old");
1610  if (old == NULL)
1611  y(null);
1612  else
1613  dump_node(gen, old, false);
1614 
1615  y(map_close);
1616 
1617  setlocale(LC_NUMERIC, "");
1618 
1619  return gen;
1620 }
1621 
1622 /*
1623  * For the workspace events we send, along with the usual "change" field, also
1624  * the workspace container in "current". For focus events, we send the
1625  * previously focused workspace in "old".
1626  */
1627 void ipc_send_workspace_event(const char *change, Con *current, Con *old) {
1628  yajl_gen gen = ipc_marshal_workspace_event(change, current, old);
1629 
1630  const unsigned char *payload;
1631  ylength length;
1632  y(get_buf, &payload, &length);
1633 
1634  ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
1635 
1636  y(free);
1637 }
1638 
1639 /*
1640  * For the window events we send, along the usual "change" field,
1641  * also the window container, in "container".
1642  */
1643 void ipc_send_window_event(const char *property, Con *con) {
1644  DLOG("Issue IPC window %s event (con = %p, window = 0x%08x)\n",
1645  property, con, (con->window ? con->window->id : XCB_WINDOW_NONE));
1646 
1647  setlocale(LC_NUMERIC, "C");
1648  yajl_gen gen = ygenalloc();
1649 
1650  y(map_open);
1651 
1652  ystr("change");
1653  ystr(property);
1654 
1655  ystr("container");
1656  dump_node(gen, con, false);
1657 
1658  y(map_close);
1659 
1660  const unsigned char *payload;
1661  ylength length;
1662  y(get_buf, &payload, &length);
1663 
1664  ipc_send_event("window", I3_IPC_EVENT_WINDOW, (const char *)payload);
1665  y(free);
1666  setlocale(LC_NUMERIC, "");
1667 }
1668 
1669 /*
1670  * For the barconfig update events, we send the serialized barconfig.
1671  */
1673  DLOG("Issue barconfig_update event for id = %s\n", barconfig->id);
1674  setlocale(LC_NUMERIC, "C");
1675  yajl_gen gen = ygenalloc();
1676 
1677  dump_bar_config(gen, barconfig);
1678 
1679  const unsigned char *payload;
1680  ylength length;
1681  y(get_buf, &payload, &length);
1682 
1683  ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (const char *)payload);
1684  y(free);
1685  setlocale(LC_NUMERIC, "");
1686 }
1687 
1688 /*
1689  * For the binding events, we send the serialized binding struct.
1690  */
1691 void ipc_send_binding_event(const char *event_type, Binding *bind) {
1692  DLOG("Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->symbol, bind->keycode);
1693 
1694  setlocale(LC_NUMERIC, "C");
1695 
1696  yajl_gen gen = ygenalloc();
1697 
1698  y(map_open);
1699 
1700  ystr("change");
1701  ystr(event_type);
1702 
1703  ystr("binding");
1704  dump_binding(gen, bind);
1705 
1706  y(map_close);
1707 
1708  const unsigned char *payload;
1709  ylength length;
1710  y(get_buf, &payload, &length);
1711 
1712  ipc_send_event("binding", I3_IPC_EVENT_BINDING, (const char *)payload);
1713 
1714  y(free);
1715  setlocale(LC_NUMERIC, "");
1716 }
1717 
1718 /*
1719  * Sends a restart reply to the IPC client on the specified fd.
1720  */
1722  DLOG("ipc_confirm_restart(fd %d)\n", client->fd);
1723  static const char *reply = "[{\"success\":true}]";
1725  client, strlen(reply), I3_IPC_REPLY_TYPE_COMMAND,
1726  (const uint8_t *)reply);
1727  ipc_push_pending(client);
1728 }
gaps_t::left
int left
Definition: data.h:153
Barbinding
Defines a mouse command to be executed instead of the default behavior when clicking on the non-statu...
Definition: configuration.h:397
ipc_client::write_callback
struct ev_io * write_callback
Definition: ipc.h:39
i3_shmlog_header::size
uint32_t size
Definition: shmlog.h:36
tree_render
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
Definition: tree.c:449
LOG
#define LOG(fmt,...)
Definition: libi3.h:94
resolve_tilde
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
con_get_fullscreen_con
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Definition: con.c:502
dump_bar_bindings
static void dump_bar_bindings(yajl_gen gen, Barconfig *config)
Definition: ipc.c:722
L_OUTPUT
@ L_OUTPUT
Definition: data.h:108
_sync_json_key
static int _sync_json_key(void *extra, const unsigned char *val, size_t len)
Definition: ipc.c:1318
current_socketpath
char * current_socketpath
Definition: ipc.c:23
SLIST_FOREACH
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:114
ipc_send_window_event
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual "change" field, also the window container,...
Definition: ipc.c:1643
Rect::y
uint32_t y
Definition: data.h:178
L_DEFAULT
@ L_DEFAULT
Definition: data.h:104
gaps_t::inner
int inner
Definition: data.h:149
i3string_as_utf8
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
Barbinding::input_code
int input_code
The button to be used (e.g., 1 for "button1").
Definition: configuration.h:399
CommandResult
A struct that contains useful information about the result of a command as a whole (e....
Definition: commands_parser.h:46
yalloc
#define yalloc(callbacks, client)
Definition: yajl_utils.h:23
path_exists
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
Definition: util.c:182
Barconfig
Holds the status bar configuration (i3bar).
Definition: configuration.h:273
ipc_client::buffer
uint8_t * buffer
Definition: ipc.h:41
Binding::input_type
input_type_t input_type
Definition: data.h:307
set_nonblock
static void set_nonblock(int sockfd)
Definition: ipc.c:34
gaps_t::bottom
int bottom
Definition: data.h:152
L_SPLITV
@ L_SPLITV
Definition: data.h:109
gaps_t
Definition: data.h:148
ipc_create_socket
int ipc_create_socket(const char *filename)
Creates the UNIX domain socket at the given path, sets it to non-blocking mode, bind()s and listen()s...
Definition: ipc.c:1544
ipc_client::buffer_size
size_t buffer_size
Definition: ipc.h:42
srealloc
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
scalloc
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
ygenalloc
#define ygenalloc()
Definition: yajl_utils.h:22
output_primary_name
char * output_primary_name(Output *output)
Retrieves the primary name of an output.
Definition: output.c:51
writeall_nonblock
ssize_t writeall_nonblock(int fd, const void *buf, size_t count)
Like writeall, but instead of retrying upon EAGAIN (returned when a write would block),...
ipc_send_binding_event
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
Definition: ipc.c:1691
Barconfig::id
char * id
Automatically generated ID for this bar config.
Definition: configuration.h:276
current_configpath
char * current_configpath
Definition: config.c:15
dump_bar_config
static void dump_bar_config(yajl_gen gen, Barconfig *config)
Definition: ipc.c:755
L_DOCKAREA
@ L_DOCKAREA
Definition: data.h:107
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:344
ipc_client
Definition: ipc.h:27
BS_PIXEL
@ BS_PIXEL
Definition: data.h:67
all_cons
struct all_cons_head all_cons
Definition: tree.c:15
ipc_send_barconfig_update_event
void ipc_send_barconfig_update_event(Barconfig *barconfig)
For the barconfig update events, we send the serialized barconfig.
Definition: ipc.c:1672
DEFAULT_DIR_MODE
#define DEFAULT_DIR_MODE
Definition: libi3.h:25
dump_event_state_mask
static void dump_event_state_mask(yajl_gen gen, Binding *bind)
Definition: ipc.c:285
IPC_HANDLER
IPC_HANDLER(run_command)
Definition: ipc.c:224
L_SPLITH
@ L_SPLITH
Definition: data.h:110
all.h
CF_OUTPUT
@ CF_OUTPUT
Definition: data.h:623
I3_XKB_GROUP_MASK_3
@ I3_XKB_GROUP_MASK_3
Definition: data.h:128
current_config
char * current_config
Definition: config.c:16
ipc_marshal_workspace_event
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old)
Generates a json workspace event.
Definition: ipc.c:1594
y
#define y(x,...)
Definition: commands.c:21
mark_t::name
char * name
Definition: data.h:627
ipc_send_shutdown_event
static void ipc_send_shutdown_event(shutdown_reason_t reason)
Definition: ipc.c:176
ipc_confirm_restart
void ipc_confirm_restart(ipc_client *client)
Sends a restart reply to the IPC client on the specified fd.
Definition: ipc.c:1721
L_TABBED
@ L_TABBED
Definition: data.h:106
ipc_client::fd
int fd
Definition: ipc.h:28
DLOG
#define DLOG(fmt,...)
Definition: libi3.h:104
ELOG
#define ELOG(fmt,...)
Definition: libi3.h:99
Con::window
struct Window * window
Definition: data.h:708
SHUTDOWN_REASON_EXIT
@ SHUTDOWN_REASON_EXIT
Definition: ipc.h:104
I3_XKB_GROUP_MASK_4
@ I3_XKB_GROUP_MASK_4
Definition: data.h:129
I3_XKB_GROUP_MASK_2
@ I3_XKB_GROUP_MASK_2
Definition: data.h:127
sync_state::rnd
uint32_t rnd
Definition: ipc.c:1314
Match::restart_mode
bool restart_mode
Definition: data.h:575
dump_binding
static void dump_binding(yajl_gen gen, Binding *bind)
Definition: ipc.c:347
mark_t
Definition: data.h:626
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:336
sstrdup
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
FREE
#define FREE(pointer)
Definition: util.h:47
add_subscription
static int add_subscription(void *extra, const unsigned char *s, ylength len)
Definition: ipc.c:1187
handler_t
void(* handler_t)(ipc_client *, uint8_t *, int, uint32_t, uint32_t)
Definition: ipc.h:58
con_orientation
orientation_t con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
Definition: con.c:1443
ipc_client::read_callback
struct ev_io * read_callback
Definition: ipc.h:38
ipc_new_client_on_fd
ipc_client * ipc_new_client_on_fd(EV_P_ int fd)
ipc_new_client_on_fd() only sets up the event handler for activity on the new connection and inserts ...
Definition: ipc.c:1519
sasprintf
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
ipc_send_event
void ipc_send_event(const char *event, uint32_t message_type, const char *payload)
Sends the specified event to all IPC clients which are currently connected and subscribed to this kin...
Definition: ipc.c:161
gaps_t::right
int right
Definition: data.h:151
canonicalize_output_name
static char * canonicalize_output_name(char *name)
Definition: ipc.c:746
xoutput
An Output is a physical output on your graphics driver.
Definition: data.h:395
Match::dock
enum Match::@15 dock
con_get_output
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on.
Definition: con.c:439
gaps_t::top
int top
Definition: data.h:150
ipc_client::timeout
struct ev_timer * timeout
Definition: ipc.h:40
con_is_internal
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
Definition: con.c:567
free_ipc_client
static void free_ipc_client(ipc_client *client, int exempt_fd)
Definition: ipc.c:131
TAILQ_HEAD_INITIALIZER
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
tray_output_t::tray_outputs
tray_outputs
Definition: configuration.h:415
Con::nodes_head
nodes_head
Definition: data.h:721
Rect::width
uint32_t width
Definition: data.h:179
L_STACKED
@ L_STACKED
Definition: data.h:105
Barbinding::command
char * command
The command which is to be executed for this button.
Definition: configuration.h:402
ipc_new_client
void ipc_new_client(EV_P_ struct ev_io *w, int revents)
Handler for activity on the listening socket, meaning that a new client has just connected and we sho...
Definition: ipc.c:1494
dump_rect
static void dump_rect(yajl_gen gen, const char *name, Rect r)
Definition: ipc.c:249
Binding::keycode
uint32_t keycode
Keycode to bind.
Definition: data.h:337
Con::type
enum Con::@20 type
state
static cmdp_state state
Definition: commands_parser.c:172
Window::id
xcb_window_t id
Definition: data.h:431
Match
A "match" is a data structure which acts like a mask or expression to match certain windows or not.
Definition: data.h:526
focused
struct Con * focused
Definition: tree.c:13
ipc_recv_message
int ipc_recv_message(int sockfd, uint32_t *message_type, uint32_t *reply_length, uint8_t **reply)
Reads a message from the given socket file descriptor and stores its length (reply_length) as well as...
sync_state::window
xcb_window_t window
Definition: ipc.c:1315
marks
struct pending_marks * marks
sync_respond
void sync_respond(xcb_window_t window, uint32_t rnd)
Definition: sync.c:12
main_loop
struct ev_loop * main_loop
Definition: main.c:66
outputs
struct outputs_head outputs
Definition: randr.c:21
I3_XKB_GROUP_MASK_1
@ I3_XKB_GROUP_MASK_1
Definition: data.h:126
YSTR_IF_SET
#define YSTR_IF_SET(name)
bindings
struct bindings_head * bindings
Definition: main.c:74
DUMP_REGEX
#define DUMP_REGEX(re_name)
Binding
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
Definition: data.h:302
Mode::name
char * name
Definition: configuration.h:83
DUMP_PROPERTY
#define DUMP_PROPERTY(key, prop_name)
all_clients
all_clients
Definition: ipc.c:26
config
Config config
Definition: config.c:17
tray_output_t
Definition: configuration.h:411
tray_output_t::output
char * output
Definition: configuration.h:412
previous_workspace_name
char * previous_workspace_name
Stores a copy of the name of the last used workspace for the workspace back-and-forth switching.
Definition: workspace.c:19
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:347
BS_NONE
@ BS_NONE
Definition: data.h:66
B_KEYBOARD
@ B_KEYBOARD
Definition: data.h:117
Binding::symbol
char * symbol
Symbol the user specified in configfile, if any.
Definition: data.h:347
ipc_socket_writeable_cb
static void ipc_socket_writeable_cb(EV_P_ struct ev_io *w, int revents)
command_result_free
void command_result_free(CommandResult *result)
Frees a CommandResult.
Definition: commands_parser.c:460
handlers
handler_t handlers[12]
Definition: ipc.c:1373
CommandResult::needs_tree_render
bool needs_tree_render
Definition: commands_parser.h:50
ipc_push_pending
static void ipc_push_pending(ipc_client *client)
Definition: ipc.c:59
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:402
_sync_json_int
static int _sync_json_int(void *extra, long long val)
Definition: ipc.c:1326
Con
A 'Con' represents everything from the X11 root window down to a single X11 window.
Definition: data.h:637
i3_version
const char * i3_version
Git commit identifier, from version.c.
Definition: version.c:13
modes
struct modes_head modes
Definition: config.c:18
Binding::event_state_mask
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
Definition: data.h:342
barconfigs
struct barconfig_head barconfigs
Definition: config.c:19
mkdirp
int mkdirp(const char *path, mode_t mode)
Emulates mkdir -p (creates any missing folders)
ipc_client_timeout
static void ipc_client_timeout(EV_P_ ev_timer *w, int revents)
Definition: ipc.c:1431
ipc_client::num_events
int num_events
Definition: ipc.h:31
header
static i3_shmlog_header * header
Definition: log.c:55
ipc_send_workspace_event
void ipc_send_workspace_event(const char *change, Con *current, Con *old)
For the workspace events we send, along with the usual "change" field, also the workspace container i...
Definition: ipc.c:1627
ipc_send_client_message
static void ipc_send_client_message(ipc_client *client, size_t size, const uint32_t message_type, const uint8_t *payload)
Definition: ipc.c:112
ylength
size_t ylength
Definition: yajl_utils.h:24
BS_NORMAL
@ BS_NORMAL
Definition: data.h:65
Con::marks_head
marks_head
Definition: data.h:698
ipc_set_kill_timeout
void ipc_set_kill_timeout(ev_tstamp new)
Set the maximum duration that we allow for a connection with an unwriteable socket.
Definition: ipc.c:49
ipc_client::events
char ** events
Definition: ipc.h:32
con_is_split
bool con_is_split(Con *con)
Returns true if a container should be considered split.
Definition: con.c:361
sync_state::last_key
char * last_key
Definition: ipc.c:1313
ipc_receive_message
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents)
Definition: ipc.c:1398
Rect::height
uint32_t height
Definition: data.h:180
shutdown_reason_t
shutdown_reason_t
Calls to ipc_shutdown() should provide a reason for the shutdown.
Definition: ipc.h:102
dump_gaps
static void dump_gaps(yajl_gen gen, const char *name, gaps_t gaps)
Definition: ipc.c:263
parse_command
CommandResult * parse_command(const char *input, yajl_gen gen, ipc_client *client)
Parses and executes the given command.
Definition: commands_parser.c:265
ipc_shutdown
void ipc_shutdown(shutdown_reason_t reason, int exempt_fd)
Calls shutdown() on each socket and closes it.
Definition: ipc.c:206
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:376
ystr
#define ystr(str)
Definition: commands.c:22
sync_state
Definition: ipc.c:1312
get_output_by_name
Output * get_output_by_name(const char *name, const bool require_active)
Returns the output with the given name or NULL.
Definition: randr.c:47
croot
struct Con * croot
Definition: tree.c:12
dump_node
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart)
Definition: ipc.c:375
Con::name
char * name
Definition: data.h:686
yajl_utils.h
Match::insert_where
enum Match::@17 insert_where
HORIZ
@ HORIZ
Definition: data.h:61
Rect::x
uint32_t x
Definition: data.h:177
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:318
Binding::command
char * command
Command, like in command mode.
Definition: data.h:356
SHUTDOWN_REASON_RESTART
@ SHUTDOWN_REASON_RESTART
Definition: ipc.h:103
workspace_is_visible
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
Definition: workspace.c:333
Barbinding::release
bool release
If true, the command will be executed after the button is released.
Definition: configuration.h:405
con_get_workspace
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Definition: con.c:453
output_get_content
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Definition: output.c:16
kill_timeout
static ev_tstamp kill_timeout
Definition: ipc.c:47
Mode
The configuration file can contain multiple sets of bindings.
Definition: configuration.h:82
Rect
Stores a rectangle, for example the size of a window, the child window etc.
Definition: data.h:176
sstrndup
char * sstrndup(const char *str, size_t size)
Safe-wrapper around strndup which exits if strndup returns NULL (meaning that there is no more memory...