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