i3
ipc.c
Go to the documentation of this file.
1 #undef I3__FILE__
2 #define I3__FILE__ "ipc.c"
3 /*
4  * vim:ts=4:sw=4:expandtab
5  *
6  * i3 - an improved dynamic tiling window manager
7  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
8  *
9  * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
10  *
11  */
12 #include "all.h"
13 #include "yajl_utils.h"
14 
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) all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
26 
27 /*
28  * Puts the given socket file descriptor into non-blocking mode or dies if
29  * setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our
30  * IPC model because we should by no means block the window manager.
31  *
32  */
33 static void set_nonblock(int sockfd) {
34  int flags = fcntl(sockfd, F_GETFL, 0);
35  flags |= O_NONBLOCK;
36  if (fcntl(sockfd, F_SETFL, flags) < 0)
37  err(-1, "Could not set O_NONBLOCK");
38 }
39 
40 /*
41  * Sends the specified event to all IPC clients which are currently connected
42  * and subscribed to this kind of event.
43  *
44  */
45 void ipc_send_event(const char *event, uint32_t message_type, const char *payload) {
46  ipc_client *current;
47  TAILQ_FOREACH(current, &all_clients, clients) {
48  /* see if this client is interested in this event */
49  bool interested = false;
50  for (int i = 0; i < current->num_events; i++) {
51  if (strcasecmp(current->events[i], event) != 0)
52  continue;
53  interested = true;
54  break;
55  }
56  if (!interested)
57  continue;
58 
59  ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t *)payload);
60  }
61 }
62 
63 /*
64  * Calls shutdown() on each socket and closes it. This function to be called
65  * when exiting or restarting only!
66  *
67  */
68 void ipc_shutdown(void) {
69  ipc_client *current;
70  while (!TAILQ_EMPTY(&all_clients)) {
71  current = TAILQ_FIRST(&all_clients);
72  shutdown(current->fd, SHUT_RDWR);
73  close(current->fd);
74  for (int i = 0; i < current->num_events; i++)
75  free(current->events[i]);
76  free(current->events);
77  TAILQ_REMOVE(&all_clients, current, clients);
78  free(current);
79  }
80 }
81 
82 /*
83  * Executes the command and returns whether it could be successfully parsed
84  * or not (at the moment, always returns true).
85  *
86  */
87 IPC_HANDLER(command) {
88  /* To get a properly terminated buffer, we copy
89  * message_size bytes out of the buffer */
90  char *command = scalloc(message_size + 1, 1);
91  strncpy(command, (const char *)message, message_size);
92  LOG("IPC: received: *%s*\n", command);
93  yajl_gen gen = yajl_gen_alloc(NULL);
94 
95  CommandResult *result = parse_command((const char *)command, gen);
96  free(command);
97 
98  if (result->needs_tree_render)
99  tree_render();
100 
101  command_result_free(result);
102 
103  const unsigned char *reply;
104  ylength length;
105  yajl_gen_get_buf(gen, &reply, &length);
106 
107  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND,
108  (const uint8_t *)reply);
109 
110  yajl_gen_free(gen);
111 }
112 
113 static void dump_rect(yajl_gen gen, const char *name, Rect r) {
114  ystr(name);
115  y(map_open);
116  ystr("x");
117  y(integer, r.x);
118  ystr("y");
119  y(integer, r.y);
120  ystr("width");
121  y(integer, r.width);
122  ystr("height");
123  y(integer, r.height);
124  y(map_close);
125 }
126 
127 static void dump_event_state_mask(yajl_gen gen, Binding *bind) {
128  y(array_open);
129  for (int i = 0; i < 20; i++) {
130  if (bind->event_state_mask & (1 << i)) {
131  switch (1 << i) {
132  case XCB_KEY_BUT_MASK_SHIFT:
133  ystr("shift");
134  break;
135  case XCB_KEY_BUT_MASK_LOCK:
136  ystr("lock");
137  break;
138  case XCB_KEY_BUT_MASK_CONTROL:
139  ystr("ctrl");
140  break;
141  case XCB_KEY_BUT_MASK_MOD_1:
142  ystr("Mod1");
143  break;
144  case XCB_KEY_BUT_MASK_MOD_2:
145  ystr("Mod2");
146  break;
147  case XCB_KEY_BUT_MASK_MOD_3:
148  ystr("Mod3");
149  break;
150  case XCB_KEY_BUT_MASK_MOD_4:
151  ystr("Mod4");
152  break;
153  case XCB_KEY_BUT_MASK_MOD_5:
154  ystr("Mod5");
155  break;
156  case XCB_KEY_BUT_MASK_BUTTON_1:
157  ystr("Button1");
158  break;
159  case XCB_KEY_BUT_MASK_BUTTON_2:
160  ystr("Button2");
161  break;
162  case XCB_KEY_BUT_MASK_BUTTON_3:
163  ystr("Button3");
164  break;
165  case XCB_KEY_BUT_MASK_BUTTON_4:
166  ystr("Button4");
167  break;
168  case XCB_KEY_BUT_MASK_BUTTON_5:
169  ystr("Button5");
170  break;
171  case (I3_XKB_GROUP_MASK_1 << 16):
172  ystr("Group1");
173  break;
174  case (I3_XKB_GROUP_MASK_2 << 16):
175  ystr("Group2");
176  break;
177  case (I3_XKB_GROUP_MASK_3 << 16):
178  ystr("Group3");
179  break;
180  case (I3_XKB_GROUP_MASK_4 << 16):
181  ystr("Group4");
182  break;
183  }
184  }
185  }
186  y(array_close);
187 }
188 
189 static void dump_binding(yajl_gen gen, Binding *bind) {
190  y(map_open);
191  ystr("input_code");
192  y(integer, bind->keycode);
193 
194  ystr("input_type");
195  ystr((const char *)(bind->input_type == B_KEYBOARD ? "keyboard" : "mouse"));
196 
197  ystr("symbol");
198  if (bind->symbol == NULL)
199  y(null);
200  else
201  ystr(bind->symbol);
202 
203  ystr("command");
204  ystr(bind->command);
205 
206  // This key is only provided for compatibility, new programs should use
207  // event_state_mask instead.
208  ystr("mods");
209  dump_event_state_mask(gen, bind);
210 
211  ystr("event_state_mask");
212  dump_event_state_mask(gen, bind);
213 
214  y(map_close);
215 }
216 
217 void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
218  y(map_open);
219  ystr("id");
220  y(integer, (long int)con);
221 
222  ystr("type");
223  switch (con->type) {
224  case CT_ROOT:
225  ystr("root");
226  break;
227  case CT_OUTPUT:
228  ystr("output");
229  break;
230  case CT_CON:
231  ystr("con");
232  break;
233  case CT_FLOATING_CON:
234  ystr("floating_con");
235  break;
236  case CT_WORKSPACE:
237  ystr("workspace");
238  break;
239  case CT_DOCKAREA:
240  ystr("dockarea");
241  break;
242  default:
243  DLOG("About to dump unknown container type=%d. This is a bug.\n", con->type);
244  assert(false);
245  break;
246  }
247 
248  /* provided for backwards compatibility only. */
249  ystr("orientation");
250  if (!con_is_split(con))
251  ystr("none");
252  else {
253  if (con_orientation(con) == HORIZ)
254  ystr("horizontal");
255  else
256  ystr("vertical");
257  }
258 
259  ystr("scratchpad_state");
260  switch (con->scratchpad_state) {
261  case SCRATCHPAD_NONE:
262  ystr("none");
263  break;
264  case SCRATCHPAD_FRESH:
265  ystr("fresh");
266  break;
267  case SCRATCHPAD_CHANGED:
268  ystr("changed");
269  break;
270  }
271 
272  ystr("percent");
273  if (con->percent == 0.0)
274  y(null);
275  else
276  y(double, con->percent);
277 
278  ystr("urgent");
279  y(bool, con->urgent);
280 
281  if (!TAILQ_EMPTY(&(con->marks_head))) {
282  ystr("marks");
283  y(array_open);
284 
285  mark_t *mark;
286  TAILQ_FOREACH(mark, &(con->marks_head), marks) {
287  ystr(mark->name);
288  }
289 
290  y(array_close);
291  }
292 
293  ystr("focused");
294  y(bool, (con == focused));
295 
296  ystr("layout");
297  switch (con->layout) {
298  case L_DEFAULT:
299  DLOG("About to dump layout=default, this is a bug in the code.\n");
300  assert(false);
301  break;
302  case L_SPLITV:
303  ystr("splitv");
304  break;
305  case L_SPLITH:
306  ystr("splith");
307  break;
308  case L_STACKED:
309  ystr("stacked");
310  break;
311  case L_TABBED:
312  ystr("tabbed");
313  break;
314  case L_DOCKAREA:
315  ystr("dockarea");
316  break;
317  case L_OUTPUT:
318  ystr("output");
319  break;
320  }
321 
322  ystr("workspace_layout");
323  switch (con->workspace_layout) {
324  case L_DEFAULT:
325  ystr("default");
326  break;
327  case L_STACKED:
328  ystr("stacked");
329  break;
330  case L_TABBED:
331  ystr("tabbed");
332  break;
333  default:
334  DLOG("About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
335  assert(false);
336  break;
337  }
338 
339  ystr("last_split_layout");
340  switch (con->layout) {
341  case L_SPLITV:
342  ystr("splitv");
343  break;
344  default:
345  ystr("splith");
346  break;
347  }
348 
349  ystr("border");
350  switch (con->border_style) {
351  case BS_NORMAL:
352  ystr("normal");
353  break;
354  case BS_NONE:
355  ystr("none");
356  break;
357  case BS_PIXEL:
358  ystr("pixel");
359  break;
360  }
361 
362  ystr("current_border_width");
363  y(integer, con->current_border_width);
364 
365  dump_rect(gen, "rect", con->rect);
366  dump_rect(gen, "deco_rect", con->deco_rect);
367  dump_rect(gen, "window_rect", con->window_rect);
368  dump_rect(gen, "geometry", con->geometry);
369 
370  ystr("name");
371  if (con->window && con->window->name)
372  ystr(i3string_as_utf8(con->window->name));
373  else if (con->name != NULL)
374  ystr(con->name);
375  else
376  y(null);
377 
378  if (con->title_format != NULL) {
379  ystr("title_format");
380  ystr(con->title_format);
381  }
382 
383  if (con->type == CT_WORKSPACE) {
384  ystr("num");
385  y(integer, con->num);
386  }
387 
388  ystr("window");
389  if (con->window)
390  y(integer, con->window->id);
391  else
392  y(null);
393 
394  if (con->window && !inplace_restart) {
395  /* Window properties are useless to preserve when restarting because
396  * they will be queried again anyway. However, for i3-save-tree(1),
397  * they are very useful and save i3-save-tree dealing with X11. */
398  ystr("window_properties");
399  y(map_open);
400 
401 #define DUMP_PROPERTY(key, prop_name) \
402  do { \
403  if (con->window->prop_name != NULL) { \
404  ystr(key); \
405  ystr(con->window->prop_name); \
406  } \
407  } while (0)
408 
409  DUMP_PROPERTY("class", class_class);
410  DUMP_PROPERTY("instance", class_instance);
411  DUMP_PROPERTY("window_role", role);
412 
413  if (con->window->name != NULL) {
414  ystr("title");
415  ystr(i3string_as_utf8(con->window->name));
416  }
417 
418  ystr("transient_for");
419  if (con->window->transient_for == XCB_NONE)
420  y(null);
421  else
422  y(integer, con->window->transient_for);
423 
424  y(map_close);
425  }
426 
427  ystr("nodes");
428  y(array_open);
429  Con *node;
430  if (con->type != CT_DOCKAREA || !inplace_restart) {
431  TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
432  dump_node(gen, node, inplace_restart);
433  }
434  }
435  y(array_close);
436 
437  ystr("floating_nodes");
438  y(array_open);
439  TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
440  dump_node(gen, node, inplace_restart);
441  }
442  y(array_close);
443 
444  ystr("focus");
445  y(array_open);
446  TAILQ_FOREACH(node, &(con->focus_head), focused) {
447  y(integer, (long int)node);
448  }
449  y(array_close);
450 
451  ystr("fullscreen_mode");
452  y(integer, con->fullscreen_mode);
453 
454  ystr("sticky");
455  y(bool, con->sticky);
456 
457  ystr("floating");
458  switch (con->floating) {
459  case FLOATING_AUTO_OFF:
460  ystr("auto_off");
461  break;
462  case FLOATING_AUTO_ON:
463  ystr("auto_on");
464  break;
465  case FLOATING_USER_OFF:
466  ystr("user_off");
467  break;
468  case FLOATING_USER_ON:
469  ystr("user_on");
470  break;
471  }
472 
473  ystr("swallows");
474  y(array_open);
475  Match *match;
476  TAILQ_FOREACH(match, &(con->swallow_head), matches) {
477  /* We will generate a new restart_mode match specification after this
478  * loop, so skip this one. */
479  if (match->restart_mode)
480  continue;
481  y(map_open);
482  if (match->dock != -1) {
483  ystr("dock");
484  y(integer, match->dock);
485  ystr("insert_where");
486  y(integer, match->insert_where);
487  }
488 
489 #define DUMP_REGEX(re_name) \
490  do { \
491  if (match->re_name != NULL) { \
492  ystr(#re_name); \
493  ystr(match->re_name->pattern); \
494  } \
495  } while (0)
496 
497  DUMP_REGEX(class);
498  DUMP_REGEX(instance);
499  DUMP_REGEX(window_role);
500  DUMP_REGEX(title);
501 
502 #undef DUMP_REGEX
503  y(map_close);
504  }
505 
506  if (inplace_restart) {
507  if (con->window != NULL) {
508  y(map_open);
509  ystr("id");
510  y(integer, con->window->id);
511  ystr("restart_mode");
512  y(bool, true);
513  y(map_close);
514  }
515  }
516  y(array_close);
517 
518  if (inplace_restart && con->window != NULL) {
519  ystr("depth");
520  y(integer, con->depth);
521  }
522 
523  y(map_close);
524 }
525 
526 static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
527  if (TAILQ_EMPTY(&(config->bar_bindings)))
528  return;
529 
530  ystr("bindings");
531  y(array_open);
532 
533  struct Barbinding *current;
534  TAILQ_FOREACH(current, &(config->bar_bindings), bindings) {
535  y(map_open);
536 
537  ystr("input_code");
538  y(integer, current->input_code);
539  ystr("command");
540  ystr(current->command);
541 
542  y(map_close);
543  }
544 
545  y(array_close);
546 }
547 
548 static void dump_bar_config(yajl_gen gen, Barconfig *config) {
549  y(map_open);
550 
551  ystr("id");
552  ystr(config->id);
553 
554  if (config->num_outputs > 0) {
555  ystr("outputs");
556  y(array_open);
557  for (int c = 0; c < config->num_outputs; c++)
558  ystr(config->outputs[c]);
559  y(array_close);
560  }
561 
562  if (!TAILQ_EMPTY(&(config->tray_outputs))) {
563  ystr("tray_outputs");
564  y(array_open);
565 
566  struct tray_output_t *tray_output;
567  TAILQ_FOREACH(tray_output, &(config->tray_outputs), tray_outputs) {
568  ystr(tray_output->output);
569  }
570 
571  y(array_close);
572  }
573 
574 #define YSTR_IF_SET(name) \
575  do { \
576  if (config->name) { \
577  ystr(#name); \
578  ystr(config->name); \
579  } \
580  } while (0)
581 
582  ystr("tray_padding");
583  y(integer, config->tray_padding);
584 
585  YSTR_IF_SET(socket_path);
586 
587  ystr("mode");
588  switch (config->mode) {
589  case M_HIDE:
590  ystr("hide");
591  break;
592  case M_INVISIBLE:
593  ystr("invisible");
594  break;
595  case M_DOCK:
596  default:
597  ystr("dock");
598  break;
599  }
600 
601  ystr("hidden_state");
602  switch (config->hidden_state) {
603  case S_SHOW:
604  ystr("show");
605  break;
606  case S_HIDE:
607  default:
608  ystr("hide");
609  break;
610  }
611 
612  ystr("modifier");
613  switch (config->modifier) {
614  case M_NONE:
615  ystr("none");
616  break;
617  case M_CONTROL:
618  ystr("ctrl");
619  break;
620  case M_SHIFT:
621  ystr("shift");
622  break;
623  case M_MOD1:
624  ystr("Mod1");
625  break;
626  case M_MOD2:
627  ystr("Mod2");
628  break;
629  case M_MOD3:
630  ystr("Mod3");
631  break;
632  case M_MOD5:
633  ystr("Mod5");
634  break;
635  default:
636  ystr("Mod4");
637  break;
638  }
639 
640  dump_bar_bindings(gen, config);
641 
642  ystr("position");
643  if (config->position == P_BOTTOM)
644  ystr("bottom");
645  else
646  ystr("top");
647 
648  YSTR_IF_SET(status_command);
649  YSTR_IF_SET(font);
650 
651  if (config->separator_symbol) {
652  ystr("separator_symbol");
653  ystr(config->separator_symbol);
654  }
655 
656  ystr("workspace_buttons");
657  y(bool, !config->hide_workspace_buttons);
658 
659  ystr("strip_workspace_numbers");
660  y(bool, config->strip_workspace_numbers);
661 
662  ystr("binding_mode_indicator");
663  y(bool, !config->hide_binding_mode_indicator);
664 
665  ystr("verbose");
666  y(bool, config->verbose);
667 
668 #undef YSTR_IF_SET
669 #define YSTR_IF_SET(name) \
670  do { \
671  if (config->colors.name) { \
672  ystr(#name); \
673  ystr(config->colors.name); \
674  } \
675  } while (0)
676 
677  ystr("colors");
678  y(map_open);
679  YSTR_IF_SET(background);
680  YSTR_IF_SET(statusline);
681  YSTR_IF_SET(separator);
682  YSTR_IF_SET(focused_background);
683  YSTR_IF_SET(focused_statusline);
684  YSTR_IF_SET(focused_separator);
685  YSTR_IF_SET(focused_workspace_border);
686  YSTR_IF_SET(focused_workspace_bg);
687  YSTR_IF_SET(focused_workspace_text);
688  YSTR_IF_SET(active_workspace_border);
689  YSTR_IF_SET(active_workspace_bg);
690  YSTR_IF_SET(active_workspace_text);
691  YSTR_IF_SET(inactive_workspace_border);
692  YSTR_IF_SET(inactive_workspace_bg);
693  YSTR_IF_SET(inactive_workspace_text);
694  YSTR_IF_SET(urgent_workspace_border);
695  YSTR_IF_SET(urgent_workspace_bg);
696  YSTR_IF_SET(urgent_workspace_text);
697  YSTR_IF_SET(binding_mode_border);
698  YSTR_IF_SET(binding_mode_bg);
699  YSTR_IF_SET(binding_mode_text);
700  y(map_close);
701 
702  y(map_close);
703 #undef YSTR_IF_SET
704 }
705 
706 IPC_HANDLER(tree) {
707  setlocale(LC_NUMERIC, "C");
708  yajl_gen gen = ygenalloc();
709  dump_node(gen, croot, false);
710  setlocale(LC_NUMERIC, "");
711 
712  const unsigned char *payload;
713  ylength length;
714  y(get_buf, &payload, &length);
715 
716  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload);
717  y(free);
718 }
719 
720 /*
721  * Formats the reply message for a GET_WORKSPACES request and sends it to the
722  * client
723  *
724  */
725 IPC_HANDLER(get_workspaces) {
726  yajl_gen gen = ygenalloc();
727  y(array_open);
728 
729  Con *focused_ws = con_get_workspace(focused);
730 
731  Con *output;
732  TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
733  if (con_is_internal(output))
734  continue;
735  Con *ws;
736  TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
737  assert(ws->type == CT_WORKSPACE);
738  y(map_open);
739 
740  ystr("num");
741  y(integer, ws->num);
742 
743  ystr("name");
744  ystr(ws->name);
745 
746  ystr("visible");
747  y(bool, workspace_is_visible(ws));
748 
749  ystr("focused");
750  y(bool, ws == focused_ws);
751 
752  ystr("rect");
753  y(map_open);
754  ystr("x");
755  y(integer, ws->rect.x);
756  ystr("y");
757  y(integer, ws->rect.y);
758  ystr("width");
759  y(integer, ws->rect.width);
760  ystr("height");
761  y(integer, ws->rect.height);
762  y(map_close);
763 
764  ystr("output");
765  ystr(output->name);
766 
767  ystr("urgent");
768  y(bool, ws->urgent);
769 
770  y(map_close);
771  }
772  }
773 
774  y(array_close);
775 
776  const unsigned char *payload;
777  ylength length;
778  y(get_buf, &payload, &length);
779 
780  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
781  y(free);
782 }
783 
784 /*
785  * Formats the reply message for a GET_OUTPUTS request and sends it to the
786  * client
787  *
788  */
789 IPC_HANDLER(get_outputs) {
790  yajl_gen gen = ygenalloc();
791  y(array_open);
792 
793  Output *output;
794  TAILQ_FOREACH(output, &outputs, outputs) {
795  y(map_open);
796 
797  ystr("name");
798  ystr(output->name);
799 
800  ystr("active");
801  y(bool, output->active);
802 
803  ystr("primary");
804  y(bool, output->primary);
805 
806  ystr("rect");
807  y(map_open);
808  ystr("x");
809  y(integer, output->rect.x);
810  ystr("y");
811  y(integer, output->rect.y);
812  ystr("width");
813  y(integer, output->rect.width);
814  ystr("height");
815  y(integer, output->rect.height);
816  y(map_close);
817 
818  ystr("current_workspace");
819  Con *ws = NULL;
820  if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
821  ystr(ws->name);
822  else
823  y(null);
824 
825  y(map_close);
826  }
827 
828  y(array_close);
829 
830  const unsigned char *payload;
831  ylength length;
832  y(get_buf, &payload, &length);
833 
834  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
835  y(free);
836 }
837 
838 /*
839  * Formats the reply message for a GET_MARKS request and sends it to the
840  * client
841  *
842  */
843 IPC_HANDLER(get_marks) {
844  yajl_gen gen = ygenalloc();
845  y(array_open);
846 
847  Con *con;
849  mark_t *mark;
850  TAILQ_FOREACH(mark, &(con->marks_head), marks) {
851  ystr(mark->name);
852  }
853  }
854 
855  y(array_close);
856 
857  const unsigned char *payload;
858  ylength length;
859  y(get_buf, &payload, &length);
860 
861  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload);
862  y(free);
863 }
864 
865 /*
866  * Returns the version of i3
867  *
868  */
869 IPC_HANDLER(get_version) {
870  yajl_gen gen = ygenalloc();
871  y(map_open);
872 
873  ystr("major");
874  y(integer, MAJOR_VERSION);
875 
876  ystr("minor");
877  y(integer, MINOR_VERSION);
878 
879  ystr("patch");
880  y(integer, PATCH_VERSION);
881 
882  ystr("human_readable");
883  ystr(i3_version);
884 
885  ystr("loaded_config_file_name");
887 
888  y(map_close);
889 
890  const unsigned char *payload;
891  ylength length;
892  y(get_buf, &payload, &length);
893 
894  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload);
895  y(free);
896 }
897 
898 /*
899  * Formats the reply message for a GET_BAR_CONFIG request and sends it to the
900  * client.
901  *
902  */
903 IPC_HANDLER(get_bar_config) {
904  yajl_gen gen = ygenalloc();
905 
906  /* If no ID was passed, we return a JSON array with all IDs */
907  if (message_size == 0) {
908  y(array_open);
909  Barconfig *current;
910  TAILQ_FOREACH(current, &barconfigs, configs) {
911  ystr(current->id);
912  }
913  y(array_close);
914 
915  const unsigned char *payload;
916  ylength length;
917  y(get_buf, &payload, &length);
918 
919  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
920  y(free);
921  return;
922  }
923 
924  /* To get a properly terminated buffer, we copy
925  * message_size bytes out of the buffer */
926  char *bar_id = NULL;
927  sasprintf(&bar_id, "%.*s", message_size, message);
928  LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id);
929  Barconfig *current, *config = NULL;
930  TAILQ_FOREACH(current, &barconfigs, configs) {
931  if (strcmp(current->id, bar_id) != 0)
932  continue;
933 
934  config = current;
935  break;
936  }
937  free(bar_id);
938 
939  if (!config) {
940  /* If we did not find a config for the given ID, the reply will contain
941  * a null 'id' field. */
942  y(map_open);
943 
944  ystr("id");
945  y(null);
946 
947  y(map_close);
948  } else {
949  dump_bar_config(gen, config);
950  }
951 
952  const unsigned char *payload;
953  ylength length;
954  y(get_buf, &payload, &length);
955 
956  ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
957  y(free);
958 }
959 
960 /*
961  * Callback for the YAJL parser (will be called when a string is parsed).
962  *
963  */
964 static int add_subscription(void *extra, const unsigned char *s,
965  ylength len) {
966  ipc_client *client = extra;
967 
968  DLOG("should add subscription to extra %p, sub %.*s\n", client, (int)len, s);
969  int event = client->num_events;
970 
971  client->num_events++;
972  client->events = srealloc(client->events, client->num_events * sizeof(char *));
973  /* We copy the string because it is not null-terminated and strndup()
974  * is missing on some BSD systems */
975  client->events[event] = scalloc(len + 1, 1);
976  memcpy(client->events[event], s, len);
977 
978  DLOG("client is now subscribed to:\n");
979  for (int i = 0; i < client->num_events; i++)
980  DLOG("event %s\n", client->events[i]);
981  DLOG("(done)\n");
982 
983  return 1;
984 }
985 
986 /*
987  * Subscribes this connection to the event types which were given as a JSON
988  * serialized array in the payload field of the message.
989  *
990  */
991 IPC_HANDLER(subscribe) {
992  yajl_handle p;
993  yajl_status stat;
994  ipc_client *current, *client = NULL;
995 
996  /* Search the ipc_client structure for this connection */
997  TAILQ_FOREACH(current, &all_clients, clients) {
998  if (current->fd != fd)
999  continue;
1000 
1001  client = current;
1002  break;
1003  }
1004 
1005  if (client == NULL) {
1006  ELOG("Could not find ipc_client data structure for fd %d\n", fd);
1007  return;
1008  }
1009 
1010  /* Setup the JSON parser */
1011  static yajl_callbacks callbacks = {
1012  .yajl_string = add_subscription,
1013  };
1014 
1015  p = yalloc(&callbacks, (void *)client);
1016  stat = yajl_parse(p, (const unsigned char *)message, message_size);
1017  if (stat != yajl_status_ok) {
1018  unsigned char *err;
1019  err = yajl_get_error(p, true, (const unsigned char *)message,
1020  message_size);
1021  ELOG("YAJL parse error: %s\n", err);
1022  yajl_free_error(p, err);
1023 
1024  const char *reply = "{\"success\":false}";
1025  ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
1026  yajl_free(p);
1027  return;
1028  }
1029  yajl_free(p);
1030  const char *reply = "{\"success\":true}";
1031  ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
1032 }
1033 
1034 /* The index of each callback function corresponds to the numeric
1035  * value of the message type (see include/i3/ipc.h) */
1037  handle_command,
1038  handle_get_workspaces,
1039  handle_subscribe,
1040  handle_get_outputs,
1041  handle_tree,
1042  handle_get_marks,
1043  handle_get_bar_config,
1044  handle_get_version,
1045 };
1046 
1047 /*
1048  * Handler for activity on a client connection, receives a message from a
1049  * client.
1050  *
1051  * For now, the maximum message size is 2048. I’m not sure for what the
1052  * IPC interface will be used in the future, thus I’m not implementing a
1053  * mechanism for arbitrarily long messages, as it seems like overkill
1054  * at the moment.
1055  *
1056  */
1057 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
1058  uint32_t message_type;
1059  uint32_t message_length;
1060  uint8_t *message = NULL;
1061 
1062  int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message);
1063  /* EOF or other error */
1064  if (ret < 0) {
1065  /* Was this a spurious read? See ev(3) */
1066  if (ret == -1 && errno == EAGAIN) {
1067  FREE(message);
1068  return;
1069  }
1070 
1071  /* If not, there was some kind of error. We don’t bother
1072  * and close the connection */
1073  close(w->fd);
1074 
1075  /* Delete the client from the list of clients */
1076  ipc_client *current;
1077  TAILQ_FOREACH(current, &all_clients, clients) {
1078  if (current->fd != w->fd)
1079  continue;
1080 
1081  for (int i = 0; i < current->num_events; i++)
1082  free(current->events[i]);
1083  free(current->events);
1084  /* We can call TAILQ_REMOVE because we break out of the
1085  * TAILQ_FOREACH afterwards */
1086  TAILQ_REMOVE(&all_clients, current, clients);
1087  free(current);
1088  break;
1089  }
1090 
1091  ev_io_stop(EV_A_ w);
1092  free(w);
1093  FREE(message);
1094 
1095  DLOG("IPC: client disconnected\n");
1096  return;
1097  }
1098 
1099  if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
1100  DLOG("Unhandled message type: %d\n", message_type);
1101  else {
1102  handler_t h = handlers[message_type];
1103  h(w->fd, message, 0, message_length, message_type);
1104  }
1105 
1106  FREE(message);
1107 }
1108 
1109 /*
1110  * Handler for activity on the listening socket, meaning that a new client
1111  * has just connected and we should accept() him. Sets up the event handler
1112  * for activity on the new connection and inserts the file descriptor into
1113  * the list of clients.
1114  *
1115  */
1116 void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
1117  struct sockaddr_un peer;
1118  socklen_t len = sizeof(struct sockaddr_un);
1119  int client;
1120  if ((client = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) {
1121  if (errno == EINTR)
1122  return;
1123  else
1124  perror("accept()");
1125  return;
1126  }
1127 
1128  /* Close this file descriptor on exec() */
1129  (void)fcntl(client, F_SETFD, FD_CLOEXEC);
1130 
1131  set_nonblock(client);
1132 
1133  struct ev_io *package = scalloc(1, sizeof(struct ev_io));
1134  ev_io_init(package, ipc_receive_message, client, EV_READ);
1135  ev_io_start(EV_A_ package);
1136 
1137  DLOG("IPC: new client connected on fd %d\n", w->fd);
1138 
1139  ipc_client *new = scalloc(1, sizeof(ipc_client));
1140  new->fd = client;
1141 
1142  TAILQ_INSERT_TAIL(&all_clients, new, clients);
1143 }
1144 
1145 /*
1146  * Creates the UNIX domain socket at the given path, sets it to non-blocking
1147  * mode, bind()s and listen()s on it.
1148  *
1149  */
1150 int ipc_create_socket(const char *filename) {
1151  int sockfd;
1152 
1154 
1155  char *resolved = resolve_tilde(filename);
1156  DLOG("Creating IPC-socket at %s\n", resolved);
1157  char *copy = sstrdup(resolved);
1158  const char *dir = dirname(copy);
1159  if (!path_exists(dir))
1160  mkdirp(dir, DEFAULT_DIR_MODE);
1161  free(copy);
1162 
1163  /* Unlink the unix domain socket before */
1164  unlink(resolved);
1165 
1166  if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
1167  perror("socket()");
1168  free(resolved);
1169  return -1;
1170  }
1171 
1172  (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
1173 
1174  struct sockaddr_un addr;
1175  memset(&addr, 0, sizeof(struct sockaddr_un));
1176  addr.sun_family = AF_LOCAL;
1177  strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1);
1178  if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
1179  perror("bind()");
1180  free(resolved);
1181  return -1;
1182  }
1183 
1184  set_nonblock(sockfd);
1185 
1186  if (listen(sockfd, 5) < 0) {
1187  perror("listen()");
1188  free(resolved);
1189  return -1;
1190  }
1191 
1192  current_socketpath = resolved;
1193  return sockfd;
1194 }
1195 
1196 /*
1197  * Generates a json workspace event. Returns a dynamically allocated yajl
1198  * generator. Free with yajl_gen_free().
1199  */
1200 yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) {
1201  setlocale(LC_NUMERIC, "C");
1202  yajl_gen gen = ygenalloc();
1203 
1204  y(map_open);
1205 
1206  ystr("change");
1207  ystr(change);
1208 
1209  ystr("current");
1210  if (current == NULL)
1211  y(null);
1212  else
1213  dump_node(gen, current, false);
1214 
1215  ystr("old");
1216  if (old == NULL)
1217  y(null);
1218  else
1219  dump_node(gen, old, false);
1220 
1221  y(map_close);
1222 
1223  setlocale(LC_NUMERIC, "");
1224 
1225  return gen;
1226 }
1227 
1228 /*
1229  * For the workspace events we send, along with the usual "change" field, also
1230  * the workspace container in "current". For focus events, we send the
1231  * previously focused workspace in "old".
1232  */
1233 void ipc_send_workspace_event(const char *change, Con *current, Con *old) {
1234  yajl_gen gen = ipc_marshal_workspace_event(change, current, old);
1235 
1236  const unsigned char *payload;
1237  ylength length;
1238  y(get_buf, &payload, &length);
1239 
1240  ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
1241 
1242  y(free);
1243 }
1244 
1249 void ipc_send_window_event(const char *property, Con *con) {
1250  DLOG("Issue IPC window %s event (con = %p, window = 0x%08x)\n",
1251  property, con, (con->window ? con->window->id : XCB_WINDOW_NONE));
1252 
1253  setlocale(LC_NUMERIC, "C");
1254  yajl_gen gen = ygenalloc();
1255 
1256  y(map_open);
1257 
1258  ystr("change");
1259  ystr(property);
1260 
1261  ystr("container");
1262  dump_node(gen, con, false);
1263 
1264  y(map_close);
1265 
1266  const unsigned char *payload;
1267  ylength length;
1268  y(get_buf, &payload, &length);
1269 
1270  ipc_send_event("window", I3_IPC_EVENT_WINDOW, (const char *)payload);
1271  y(free);
1272  setlocale(LC_NUMERIC, "");
1273 }
1274 
1279  DLOG("Issue barconfig_update event for id = %s\n", barconfig->id);
1280  setlocale(LC_NUMERIC, "C");
1281  yajl_gen gen = ygenalloc();
1282 
1283  dump_bar_config(gen, barconfig);
1284 
1285  const unsigned char *payload;
1286  ylength length;
1287  y(get_buf, &payload, &length);
1288 
1289  ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (const char *)payload);
1290  y(free);
1291  setlocale(LC_NUMERIC, "");
1292 }
1293 
1294 /*
1295  * For the binding events, we send the serialized binding struct.
1296  */
1297 void ipc_send_binding_event(const char *event_type, Binding *bind) {
1298  DLOG("Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->symbol, bind->keycode);
1299 
1300  setlocale(LC_NUMERIC, "C");
1301 
1302  yajl_gen gen = ygenalloc();
1303 
1304  y(map_open);
1305 
1306  ystr("change");
1307  ystr(event_type);
1308 
1309  ystr("binding");
1310  dump_binding(gen, bind);
1311 
1312  y(map_close);
1313 
1314  const unsigned char *payload;
1315  ylength length;
1316  y(get_buf, &payload, &length);
1317 
1318  ipc_send_event("binding", I3_IPC_EVENT_BINDING, (const char *)payload);
1319 
1320  y(free);
1321  setlocale(LC_NUMERIC, "");
1322 }
uint32_t height
Definition: data.h:145
uint32_t x
Definition: data.h:142
Definition: data.h:61
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...
#define IPC_HANDLER(name)
Definition: ipc.h:48
Definition: data.h:63
enum Match::@15 dock
enum Barconfig::@10 modifier
Bar modifier (to show bar when in hide mode).
char * name
Definition: data.h:535
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
Definition: data.h:574
Definition: data.h:534
struct Window * window
Definition: data.h:611
int fd
Definition: ipc.h:26
char * name
Definition: data.h:590
Definition: data.h:87
char * command
The command which is to be executed for this button.
Definition: config.h:366
char * symbol
Symbol the user specified in configfile, if any.
Definition: data.h:291
char ** outputs
Outputs on which this bar should show up on.
Definition: config.h:250
#define TAILQ_EMPTY(head)
Definition: queue.h:344
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Definition: output.c:18
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
Definition: con.c:467
enum Barconfig::@8 mode
Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mo...
void ipc_send_barconfig_update_event(Barconfig *barconfig)
For the barconfig update events, we send the serialized barconfig.
Definition: ipc.c:1278
struct bindings_head * bindings
Definition: main.c:73
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents)
Definition: ipc.c:1057
bool urgent
Definition: data.h:549
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:347
enum Barconfig::@9 hidden_state
struct barconfig_head barconfigs
Definition: config.c:19
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
Definition: ipc.c:1297
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...
Definition: data.h:85
#define ystr(str)
Definition: commands.c:24
Config config
Definition: config.c:17
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:492
bool strip_workspace_numbers
Strip workspace numbers? Configuration option is &#39;strip_workspace_numbers yes&#39;.
Definition: config.h:314
static int add_subscription(void *extra, const unsigned char *s, ylength len)
Definition: ipc.c:964
uint32_t y
Definition: data.h:143
Definition: data.h:86
struct Con * croot
Definition: tree.c:14
#define DUMP_PROPERTY(key, prop_name)
#define ELOG(fmt,...)
Definition: libi3.h:93
char * command
Command, like in command mode.
Definition: data.h:301
uint32_t width
Definition: data.h:144
input_type_t input_type
Definition: data.h:253
static void dump_bar_bindings(yajl_gen gen, Barconfig *config)
Definition: ipc.c:526
CommandResult * parse_command(const char *input, yajl_gen gen)
Parses and executes the given command.
bool restart_mode
Definition: data.h:487
bool hide_binding_mode_indicator
Hide mode button? Configuration option is &#39;binding_mode_indicator no&#39; but we invert the bool for the ...
Definition: config.h:318
#define LOG(fmt,...)
Definition: libi3.h:88
Definition: ipc.h:25
Con * con
Pointer to the Con which represents this output.
Definition: data.h:348
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:402
bool hide_workspace_buttons
Hide workspace buttons? Configuration option is &#39;workspace_buttons no&#39; but we invert the bool to get ...
Definition: config.h:310
Definition: data.h:91
struct Rect rect
Definition: data.h:580
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart)
Definition: ipc.c:217
#define TAILQ_HEAD(name, type)
Definition: queue.h:318
bool verbose
Enable verbose mode? Useful for debugging purposes.
Definition: config.h:321
static void dump_bar_config(yajl_gen gen, Barconfig *config)
Definition: ipc.c:548
uint32_t keycode
Keycode to bind.
Definition: data.h:281
void command_result_free(CommandResult *result)
Frees a CommandResult.
int num_events
Definition: ipc.h:29
static void dump_binding(yajl_gen gen, Binding *bind)
Definition: ipc.c:189
Stores a rectangle, for example the size of a window, the child window etc.
Definition: data.h:141
Holds the status bar configuration (i3bar).
Definition: config.h:241
char * output
Definition: config.h:372
void ipc_shutdown(void)
Calls shutdown() on each socket and closes it.
Definition: ipc.c:68
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual &quot;change&quot; field, also the window container, in &quot;container&quot;.
Definition: ipc.c:1249
xcb_window_t id
Definition: data.h:362
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Definition: con.c:373
handler_t handlers[8]
Definition: ipc.c:1036
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
Definition: workspace.c:256
void(* handler_t)(int, uint8_t *, int, uint32_t, uint32_t)
Definition: ipc.h:45
orientation_t con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
Definition: con.c:1166
#define DUMP_REGEX(re_name)
int input_code
The button to be used (e.g., 1 for &quot;button1&quot;).
Definition: config.h:363
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
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:45
#define ygenalloc()
Definition: yajl_utils.h:20
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
Definition: util.c:166
enum Match::@17 insert_where
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Definition: con.c:421
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event-&gt;state for KeyPress and KeyRelease events to determine whether...
Definition: data.h:286
#define FREE(pointer)
Definition: util.h:48
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:1116
int tray_padding
Definition: config.h:258
#define yalloc(callbacks, client)
Definition: yajl_utils.h:21
char ** events
Definition: ipc.h:30
#define DLOG(fmt,...)
Definition: libi3.h:98
uint32_t y
Definition: data.h:121
A &#39;Con&#39; represents everything from the X11 root window down to a single X11 window.
Definition: data.h:544
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)
Definition: data.h:336
struct outputs_head outputs
Definition: randr.c:28
A struct that contains useful information about the result of a command as a whole (e...
#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...
bool con_is_split(Con *con)
Returns true if a container should be considered split.
Definition: con.c:281
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
enum Con::@20 type
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
static void dump_rect(yajl_gen gen, const char *name, Rect r)
Definition: ipc.c:113
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:376
Definition: data.h:59
#define DEFAULT_DIR_MODE
Definition: libi3.h:27
Rect rect
x, y, width, height
Definition: data.h:351
#define YSTR_IF_SET(name)
int mkdirp(const char *path, mode_t mode)
Emulates mkdir -p (creates any missing folders)
bool primary
Definition: data.h:342
Definition: data.h:89
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:1150
int num_outputs
Number of outputs in the outputs array.
Definition: config.h:247
char * current_configpath
Definition: config.c:16
A &quot;match&quot; is a data structure which acts like a mask or expression to match certain windows or not...
Definition: data.h:439
struct all_cons_head all_cons
Definition: tree.c:17
int ipc_send_message(int sockfd, const uint32_t message_size, const uint32_t message_type, const uint8_t *payload)
Formats a message (payload) of the given size and type and sends it to i3 via the given socket file d...
An Output is a physical output on your graphics driver.
Definition: data.h:330
Con * focused
Definition: tree.c:15
Definition: data.h:90
Defines a mouse command to be executed instead of the default behavior when clicking on the non-statu...
Definition: config.h:361
enum Barconfig::@11 position
Bar position (bottom by default).
const char * i3_version
Git commit identifier, from version.c.
Definition: version.c:11
char * name
Name of the output.
Definition: data.h:345
char * separator_symbol
A custom separator to use instead of a vertical line.
Definition: config.h:305
char * id
Automatically generated ID for this bar config.
Definition: config.h:244
size_t ylength
Definition: yajl_utils.h:22
Definition: data.h:62
char * current_socketpath
Definition: ipc.c:23
void ipc_send_workspace_event(const char *change, Con *current, Con *old)
For the workspace events we send, along with the usual &quot;change&quot; field, also the workspace container i...
Definition: ipc.c:1233
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old)
Generates a json workspace event.
Definition: ipc.c:1200
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
Definition: data.h:250
static void dump_event_state_mask(yajl_gen gen, Binding *bind)
Definition: ipc.c:127