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