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");
357 if (inplace_restart && con->window != NULL) {
359 y(integer, con->depth);
366 setlocale(LC_NUMERIC,
"C");
369 setlocale(LC_NUMERIC,
"");
371 const unsigned char *payload;
373 y(get_buf, &payload, &length);
397 assert(ws->
type == CT_WORKSPACE);
403 else y(integer, ws->
num);
412 y(
bool, ws == focused_ws);
438 const unsigned char *payload;
440 y(get_buf, &payload, &length);
471 y(integer, output->
rect.
x);
473 y(integer, output->
rect.
y);
480 ystr(
"current_workspace");
491 const unsigned char *payload;
493 y(get_buf, &payload, &length);
510 if (con->
mark != NULL)
515 const unsigned char *payload;
517 y(get_buf, &payload, &length);
532 y(integer, MAJOR_VERSION);
535 y(integer, MINOR_VERSION);
538 y(integer, PATCH_VERSION);
540 ystr(
"human_readable");
545 const unsigned char *payload;
547 y(get_buf, &payload, &length);
562 if (message_size == 0) {
570 const unsigned char *payload;
572 y(get_buf, &payload, &length);
581 char *bar_id =
scalloc(message_size + 1);
582 strncpy(bar_id, (
const char*)message, message_size);
583 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
586 if (strcmp(current->
id, bar_id) != 0)
612 #define YSTR_IF_SET(name) \
614 if (config->name) { \
616 ystr(config->name); \
624 switch (config->
mode) {
637 ystr(
"hidden_state");
686 ystr(
"workspace_buttons");
693 #define YSTR_IF_SET(name) \
695 if (config->colors.name) { \
697 ystr(config->colors.name); \
725 const unsigned char *payload;
727 y(get_buf, &payload, &length);
741 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, (
int)len, s);
749 memcpy(client->
events[event], s, len);
751 DLOG(
"client is now subscribed to:\n");
766 yajl_callbacks callbacks;
772 if (current->
fd != fd)
779 if (client == NULL) {
780 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
785 memset(&callbacks, 0,
sizeof(yajl_callbacks));
788 p =
yalloc(&callbacks, (
void*)client);
789 stat = yajl_parse(p, (
const unsigned char*)message, message_size);
790 if (stat != yajl_status_ok) {
792 err = yajl_get_error(p,
true, (
const unsigned char*)message,
794 ELOG(
"YAJL parse error: %s\n", err);
795 yajl_free_error(p, err);
797 const char *reply =
"{\"success\":false}";
798 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
803 const char *reply =
"{\"success\":true}";
804 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
811 handle_get_workspaces,
816 handle_get_bar_config,
831 uint32_t message_type;
832 uint32_t message_length;
835 int ret =
ipc_recv_message(w->fd, &message_type, &message_length, &message);
839 if (ret == -1 && errno == EAGAIN)
849 if (current->
fd != w->fd)
864 DLOG(
"IPC: client disconnected\n");
869 DLOG(
"Unhandled message type: %d\n", message_type);
872 h(w->fd, message, 0, message_length, message_type);
884 struct sockaddr_un peer;
885 socklen_t len =
sizeof(
struct sockaddr_un);
887 if ((client = accept(w->fd, (
struct sockaddr*)&peer, &len)) < 0) {
890 else perror(
"accept()");
895 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
897 set_nonblock(client);
899 struct ev_io *
package = scalloc(sizeof(struct ev_io));
901 ev_io_start(EV_A_ package);
903 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
922 DLOG(
"Creating IPC-socket at %s\n", resolved);
923 char *copy =
sstrdup(resolved);
924 const char *dir = dirname(copy);
932 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
938 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
940 struct sockaddr_un addr;
941 memset(&addr, 0,
sizeof(
struct sockaddr_un));
942 addr.sun_family = AF_LOCAL;
943 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
944 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0) {
950 set_nonblock(sockfd);
952 if (listen(sockfd, 5) < 0) {