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