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