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