2 #define I3__FILE__ "ipc.c"
15 #include <sys/socket.h>
20 #include <yajl/yajl_gen.h>
21 #include <yajl/yajl_parse.h>
33 static
void set_nonblock(
int sockfd) {
34 int flags = fcntl(sockfd, F_GETFL, 0);
36 if (fcntl(sockfd, F_SETFL, flags) < 0)
37 err(-1,
"Could not set O_NONBLOCK");
44 static bool mkdirp(
const char *path) {
45 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
47 if (errno != ENOENT) {
48 ELOG(
"mkdir(%s) failed: %s\n", path, strerror(errno));
53 while (copy[strlen(copy)-1] ==
'/')
54 copy[strlen(copy)-1] =
'\0';
56 char *sep = strrchr(copy,
'/');
75 void ipc_send_event(
const char *event, uint32_t message_type,
const char *payload) {
79 bool interested =
false;
80 for (
int i = 0; i < current->
num_events; i++) {
81 if (strcasecmp(current->
events[i], event) != 0)
102 shutdown(current->
fd, SHUT_RDWR);
117 char *command =
scalloc(message_size + 1);
118 strncpy(command, (
const char*)message, message_size);
119 LOG(
"IPC: received: *%s*\n", command);
126 const unsigned char *reply;
128 yajl_gen_get_buf(command_output->
json_gen, &reply, &length);
131 (
const uint8_t*)reply);
133 yajl_gen_free(command_output->
json_gen);
153 y(integer, (
long int)con);
156 y(integer, con->type);
165 else ystr(
"vertical");
168 ystr(
"scratchpad_state");
169 switch (con->scratchpad_state) {
170 case SCRATCHPAD_NONE:
173 case SCRATCHPAD_FRESH:
176 case SCRATCHPAD_CHANGED:
182 if (con->percent == 0.0)
184 else y(
double, con->percent);
187 y(
bool, con->urgent);
189 if (con->mark != NULL) {
198 switch (con->layout) {
200 DLOG(
"About to dump layout=default, this is a bug in the code.\n");
223 ystr(
"workspace_layout");
224 switch (con->workspace_layout) {
235 DLOG(
"About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
240 ystr(
"last_split_layout");
241 switch (con->layout) {
251 switch (con->border_style) {
263 ystr(
"current_border_width");
264 y(integer, con->current_border_width);
267 dump_rect(gen,
"window_rect", con->window_rect);
268 dump_rect(gen,
"geometry", con->geometry);
271 if (con->window && con->window->name)
276 if (con->type == CT_WORKSPACE) {
278 y(integer, con->num);
283 y(integer, con->window->id);
289 if (con->type != CT_DOCKAREA || !inplace_restart) {
296 ystr(
"floating_nodes");
298 TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
306 y(integer, (
long int)node);
310 ystr(
"fullscreen_mode");
311 y(integer, con->fullscreen_mode);
314 switch (con->floating) {
315 case FLOATING_AUTO_OFF:
318 case FLOATING_AUTO_ON:
321 case FLOATING_USER_OFF:
324 case FLOATING_USER_ON:
333 if (match->
dock != -1) {
336 y(integer, match->
dock);
337 ystr(
"insert_where");
345 if (inplace_restart) {
346 if (con->window != NULL) {
349 y(integer, con->window->id);
350 ystr(
"restart_mode");
361 setlocale(LC_NUMERIC,
"C");
364 setlocale(LC_NUMERIC,
"");
366 const unsigned char *payload;
368 y(get_buf, &payload, &length);
392 assert(ws->
type == CT_WORKSPACE);
398 else y(integer, ws->
num);
407 y(
bool, ws == focused_ws);
433 const unsigned char *payload;
435 y(get_buf, &payload, &length);
466 y(integer, output->
rect.
x);
468 y(integer, output->
rect.
y);
475 ystr(
"current_workspace");
486 const unsigned char *payload;
488 y(get_buf, &payload, &length);
505 if (con->
mark != NULL)
510 const unsigned char *payload;
512 y(get_buf, &payload, &length);
527 y(integer, MAJOR_VERSION);
530 y(integer, MINOR_VERSION);
533 y(integer, PATCH_VERSION);
535 ystr(
"human_readable");
540 const unsigned char *payload;
542 y(get_buf, &payload, &length);
557 if (message_size == 0) {
565 const unsigned char *payload;
567 y(get_buf, &payload, &length);
576 char *bar_id =
scalloc(message_size + 1);
577 strncpy(bar_id, (
const char*)message, message_size);
578 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
581 if (strcmp(current->
id, bar_id) != 0)
607 #define YSTR_IF_SET(name) \
609 if (config->name) { \
611 ystr(config->name); \
619 if (config->
mode == M_HIDE)
661 ystr(
"workspace_buttons");
668 #define YSTR_IF_SET(name) \
670 if (config->colors.name) { \
672 ystr(config->colors.name); \
699 const unsigned char *payload;
701 y(get_buf, &payload, &length);
715 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, (
int)len, s);
723 memcpy(client->
events[event], s, len);
725 DLOG(
"client is now subscribed to:\n");
740 yajl_callbacks callbacks;
746 if (current->
fd != fd)
753 if (client == NULL) {
754 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
759 memset(&callbacks, 0,
sizeof(yajl_callbacks));
762 p =
yalloc(&callbacks, (
void*)client);
763 stat = yajl_parse(p, (
const unsigned char*)message, message_size);
764 if (stat != yajl_status_ok) {
766 err = yajl_get_error(p,
true, (
const unsigned char*)message,
768 ELOG(
"YAJL parse error: %s\n", err);
769 yajl_free_error(p, err);
771 const char *reply =
"{\"success\":false}";
772 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
777 const char *reply =
"{\"success\":true}";
778 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
785 handle_get_workspaces,
790 handle_get_bar_config,
806 int n = read(w->fd, buf,
sizeof(buf));
814 if (errno == EAGAIN || errno == EWOULDBLOCK)
825 if (current->
fd != w->fd)
840 DLOG(
"IPC: client disconnected\n");
848 if (n < strlen(I3_IPC_MAGIC)) {
849 DLOG(
"IPC: message too short, ignoring\n");
853 if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
854 DLOG(
"IPC: message does not start with the IPC magic\n");
858 uint8_t *message = (uint8_t*)buf;
860 DLOG(
"IPC: n = %d\n", n);
861 message += strlen(I3_IPC_MAGIC);
862 n -= strlen(I3_IPC_MAGIC);
865 uint32_t message_size;
866 memcpy(&message_size, (uint32_t*)message,
sizeof(uint32_t));
867 message +=
sizeof(uint32_t);
868 n -=
sizeof(uint32_t);
870 if (message_size > n) {
871 DLOG(
"IPC: Either the message size was wrong or the message was not read completely, dropping\n");
876 uint32_t message_type;
877 memcpy(&message_type, (uint32_t*)message,
sizeof(uint32_t));
878 message +=
sizeof(uint32_t);
879 n -=
sizeof(uint32_t);
882 DLOG(
"Unhandled message type: %d\n", message_type);
885 h(w->fd, message, n, message_size, message_type);
888 message += message_size;
900 struct sockaddr_un peer;
901 socklen_t len =
sizeof(
struct sockaddr_un);
903 if ((client = accept(w->fd, (
struct sockaddr*)&peer, &len)) < 0) {
906 else perror(
"accept()");
911 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
913 set_nonblock(client);
915 struct ev_io *
package = scalloc(sizeof(struct ev_io));
917 ev_io_start(EV_A_ package);
919 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
938 DLOG(
"Creating IPC-socket at %s\n", resolved);
939 char *copy =
sstrdup(resolved);
940 const char *dir = dirname(copy);
948 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
954 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
956 struct sockaddr_un addr;
957 memset(&addr, 0,
sizeof(
struct sockaddr_un));
958 addr.sun_family = AF_LOCAL;
959 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
960 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0) {
966 set_nonblock(sockfd);
968 if (listen(sockfd, 5) < 0) {