2 #define I3__FILE__ "ipc.c"
14 #include <sys/socket.h>
19 #include <yajl/yajl_gen.h>
20 #include <yajl/yajl_parse.h>
21 #include <yajl/yajl_version.h>
26 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
27 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
37 static
void set_nonblock(
int sockfd) {
38 int flags = fcntl(sockfd, F_GETFL, 0);
40 if (fcntl(sockfd, F_SETFL, flags) < 0)
41 err(-1,
"Could not set O_NONBLOCK");
48 static bool mkdirp(
const char *path) {
49 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
51 if (errno != ENOENT) {
52 ELOG(
"mkdir(%s) failed: %s\n", path, strerror(errno));
55 char *copy = strdup(path);
57 while (copy[strlen(copy)-1] ==
'/')
58 copy[strlen(copy)-1] =
'\0';
60 char *sep = strrchr(copy,
'/');
79 void ipc_send_event(
const char *event, uint32_t message_type,
const char *payload) {
83 bool interested =
false;
84 for (
int i = 0; i < current->
num_events; i++) {
85 if (strcasecmp(current->
events[i], event) != 0)
106 shutdown(current->
fd, SHUT_RDWR);
121 char *command =
scalloc(message_size + 1);
122 strncpy(command, (
const char*)message, message_size);
123 LOG(
"IPC: received: *%s*\n", command);
130 const unsigned char *reply;
136 yajl_gen_get_buf(command_output->
json_gen, &reply, &length);
139 (
const uint8_t*)reply);
141 yajl_gen_free(command_output->
json_gen);
161 y(integer, (
long int)con);
164 y(integer, con->type);
173 else ystr(
"vertical");
176 ystr(
"scratchpad_state");
177 switch (con->scratchpad_state) {
178 case SCRATCHPAD_NONE:
181 case SCRATCHPAD_FRESH:
184 case SCRATCHPAD_CHANGED:
190 if (con->percent == 0.0)
192 else y(
double, con->percent);
195 y(
bool, con->urgent);
197 if (con->mark != NULL) {
209 switch (con->layout) {
211 DLOG(
"About to dump layout=default, this is a bug in the code.\n");
234 ystr(
"workspace_layout");
235 switch (con->workspace_layout) {
246 DLOG(
"About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
251 ystr(
"last_split_layout");
252 switch (con->layout) {
262 switch (con->border_style) {
275 dump_rect(gen,
"window_rect", con->window_rect);
276 dump_rect(gen,
"geometry", con->geometry);
279 if (con->window && con->window->name)
284 if (con->type == CT_WORKSPACE) {
286 y(integer, con->num);
291 y(integer, con->window->id);
297 if (con->type != CT_DOCKAREA || !inplace_restart) {
304 ystr(
"floating_nodes");
306 TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
314 y(integer, (
long int)node);
318 ystr(
"fullscreen_mode");
319 y(integer, con->fullscreen_mode);
322 switch (con->floating) {
323 case FLOATING_AUTO_OFF:
326 case FLOATING_AUTO_ON:
329 case FLOATING_USER_OFF:
332 case FLOATING_USER_ON:
341 if (match->
dock != -1) {
344 y(integer, match->
dock);
345 ystr(
"insert_where");
353 if (inplace_restart) {
354 if (con->window != NULL) {
357 y(integer, con->window->id);
358 ystr(
"restart_mode");
369 setlocale(LC_NUMERIC,
"C");
371 yajl_gen gen = yajl_gen_alloc(NULL);
373 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
376 setlocale(LC_NUMERIC,
"");
378 const unsigned char *payload;
384 y(get_buf, &payload, &length);
398 yajl_gen gen = yajl_gen_alloc(NULL);
400 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
408 if (output->
name[0] ==
'_' && output->
name[1] ==
'_')
412 assert(ws->
type == CT_WORKSPACE);
418 else y(integer, ws->
num);
427 y(
bool, ws == focused_ws);
453 const unsigned char *payload;
459 y(get_buf, &payload, &length);
472 yajl_gen gen = yajl_gen_alloc(NULL);
474 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
494 y(integer, output->
rect.
x);
496 y(integer, output->
rect.
y);
503 ystr(
"current_workspace");
514 const unsigned char *payload;
520 y(get_buf, &payload, &length);
533 yajl_gen gen = yajl_gen_alloc(NULL);
535 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
541 if (con->
mark != NULL)
546 const unsigned char *payload;
552 y(get_buf, &payload, &length);
564 yajl_gen gen = yajl_gen_alloc(NULL);
566 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
571 y(integer, MAJOR_VERSION);
574 y(integer, MINOR_VERSION);
577 y(integer, PATCH_VERSION);
579 ystr(
"human_readable");
584 const unsigned char *payload;
590 y(get_buf, &payload, &length);
603 yajl_gen gen = yajl_gen_alloc(NULL);
605 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
609 if (message_size == 0) {
617 const unsigned char *payload;
623 y(get_buf, &payload, &length);
632 char *bar_id =
scalloc(message_size + 1);
633 strncpy(bar_id, (
const char*)message, message_size);
634 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
637 if (strcmp(current->
id, bar_id) != 0)
663 #define YSTR_IF_SET(name) \
665 if (config->name) { \
667 ystr(config->name); \
675 if (config->
mode == M_HIDE)
717 ystr(
"workspace_buttons");
724 #define YSTR_IF_SET(name) \
726 if (config->colors.name) { \
728 ystr(config->colors.name); \
755 const unsigned char *payload;
761 y(get_buf, &payload, &length);
780 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, (
int)len, s);
788 memcpy(client->
events[event], s, len);
790 DLOG(
"client is now subscribed to:\n");
805 yajl_callbacks callbacks;
811 if (current->
fd != fd)
818 if (client == NULL) {
819 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
824 memset(&callbacks, 0,
sizeof(yajl_callbacks));
828 p = yajl_alloc(&callbacks, NULL, (
void*)client);
830 p = yajl_alloc(&callbacks, NULL, NULL, (
void*)client);
832 stat = yajl_parse(p, (
const unsigned char*)message, message_size);
833 if (stat != yajl_status_ok) {
835 err = yajl_get_error(p,
true, (
const unsigned char*)message,
837 ELOG(
"YAJL parse error: %s\n", err);
838 yajl_free_error(p, err);
840 const char *reply =
"{\"success\":false}";
841 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
846 const char *reply =
"{\"success\":true}";
847 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
854 handle_get_workspaces,
859 handle_get_bar_config,
875 int n = read(w->fd, buf,
sizeof(buf));
883 if (errno == EAGAIN || errno == EWOULDBLOCK)
894 if (current->
fd != w->fd)
909 DLOG(
"IPC: client disconnected\n");
917 if (n < strlen(I3_IPC_MAGIC)) {
918 DLOG(
"IPC: message too short, ignoring\n");
922 if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
923 DLOG(
"IPC: message does not start with the IPC magic\n");
927 uint8_t *message = (uint8_t*)buf;
929 DLOG(
"IPC: n = %d\n", n);
930 message += strlen(I3_IPC_MAGIC);
931 n -= strlen(I3_IPC_MAGIC);
934 uint32_t message_size;
935 memcpy(&message_size, (uint32_t*)message,
sizeof(uint32_t));
936 message +=
sizeof(uint32_t);
937 n -=
sizeof(uint32_t);
939 if (message_size > n) {
940 DLOG(
"IPC: Either the message size was wrong or the message was not read completely, dropping\n");
945 uint32_t message_type;
946 memcpy(&message_type, (uint32_t*)message,
sizeof(uint32_t));
947 message +=
sizeof(uint32_t);
948 n -=
sizeof(uint32_t);
950 if (message_type >= (
sizeof(handlers) /
sizeof(
handler_t)))
951 DLOG(
"Unhandled message type: %d\n", message_type);
954 h(w->fd, message, n, message_size, message_type);
957 message += message_size;
969 struct sockaddr_un peer;
970 socklen_t len =
sizeof(
struct sockaddr_un);
972 if ((client = accept(w->fd, (
struct sockaddr*)&peer, &len)) < 0) {
975 else perror(
"accept()");
980 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
982 set_nonblock(client);
984 struct ev_io *
package = scalloc(sizeof(struct ev_io));
986 ev_io_start(EV_A_ package);
988 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
1007 DLOG(
"Creating IPC-socket at %s\n", resolved);
1008 char *copy =
sstrdup(resolved);
1009 const char *dir = dirname(copy);
1017 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
1023 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
1025 struct sockaddr_un addr;
1026 memset(&addr, 0,
sizeof(
struct sockaddr_un));
1027 addr.sun_family = AF_LOCAL;
1028 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
1029 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0) {
1035 set_nonblock(sockfd);
1037 if (listen(sockfd, 5) < 0) {