12 #include <sys/socket.h>
17 #include <yajl/yajl_gen.h>
18 #include <yajl/yajl_parse.h>
19 #include <yajl/yajl_version.h>
24 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
25 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
35 static
void set_nonblock(
int sockfd) {
36 int flags = fcntl(sockfd, F_GETFL, 0);
38 if (fcntl(sockfd, F_SETFL, flags) < 0)
39 err(-1,
"Could not set O_NONBLOCK");
46 static bool mkdirp(
const char *path) {
47 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
49 if (errno != ENOENT) {
50 ELOG(
"mkdir(%s) failed: %s\n", path, strerror(errno));
53 char *copy = strdup(path);
55 while (copy[strlen(copy)-1] ==
'/')
56 copy[strlen(copy)-1] =
'\0';
58 char *sep = strrchr(copy,
'/');
77 void ipc_send_event(
const char *event, uint32_t message_type,
const char *payload) {
81 bool interested =
false;
82 for (
int i = 0; i < current->
num_events; i++) {
83 if (strcasecmp(current->
events[i], event) != 0)
104 shutdown(current->
fd, SHUT_RDWR);
119 char *command =
scalloc(message_size + 1);
120 strncpy(command, (
const char*)message, message_size);
121 LOG(
"IPC: received: *%s*\n", command);
130 I3_IPC_REPLY_TYPE_COMMAND,
153 y(integer, (
long int)con);
156 y(integer, con->type);
159 switch (con->orientation) {
171 ystr(
"scratchpad_state");
172 switch (con->scratchpad_state) {
173 case SCRATCHPAD_NONE:
176 case SCRATCHPAD_FRESH:
179 case SCRATCHPAD_CHANGED:
185 if (con->percent == 0.0)
187 else y(
double, con->percent);
190 y(
bool, con->urgent);
192 if (con->mark != NULL) {
201 switch (con->layout) {
220 switch (con->border_style) {
233 dump_rect(gen,
"window_rect", con->window_rect);
234 dump_rect(gen,
"geometry", con->geometry);
237 if (con->window && con->window->name_json)
238 ystr(con->window->name_json);
242 if (con->type == CT_WORKSPACE) {
244 y(integer, con->num);
249 y(integer, con->window->id);
255 if (con->type != CT_DOCKAREA || !inplace_restart) {
262 ystr(
"floating_nodes");
264 TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
272 y(integer, (
long int)node);
276 ystr(
"fullscreen_mode");
277 y(integer, con->fullscreen_mode);
280 switch (con->floating) {
281 case FLOATING_AUTO_OFF:
284 case FLOATING_AUTO_ON:
287 case FLOATING_USER_OFF:
290 case FLOATING_USER_ON:
299 if (match->
dock != -1) {
302 y(integer, match->
dock);
303 ystr(
"insert_where");
311 if (inplace_restart) {
312 if (con->window != NULL) {
315 y(integer, con->window->id);
316 ystr(
"restart_mode");
327 setlocale(LC_NUMERIC,
"C");
329 yajl_gen gen = yajl_gen_alloc(NULL);
331 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
334 setlocale(LC_NUMERIC,
"");
336 const unsigned char *payload;
342 y(get_buf, &payload, &length);
356 yajl_gen gen = yajl_gen_alloc(NULL);
358 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
366 if (output->
name[0] ==
'_' && output->
name[1] ==
'_')
370 assert(ws->
type == CT_WORKSPACE);
376 else y(integer, ws->
num);
385 y(
bool, ws == focused_ws);
411 const unsigned char *payload;
417 y(get_buf, &payload, &length);
430 yajl_gen gen = yajl_gen_alloc(NULL);
432 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
452 y(integer, output->
rect.
x);
454 y(integer, output->
rect.
y);
461 ystr(
"current_workspace");
472 const unsigned char *payload;
478 y(get_buf, &payload, &length);
491 yajl_gen gen = yajl_gen_alloc(NULL);
493 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
499 if (con->
mark != NULL)
504 const unsigned char *payload;
510 y(get_buf, &payload, &length);
523 yajl_gen gen = yajl_gen_alloc(NULL);
525 yajl_gen gen = yajl_gen_alloc(NULL, NULL);
529 if (message_size == 0) {
537 const unsigned char *payload;
543 y(get_buf, &payload, &length);
552 char *bar_id =
scalloc(message_size + 1);
553 strncpy(bar_id, (
const char*)message, message_size);
554 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
557 if (strcmp(current->
id, bar_id) != 0)
583 #define YSTR_IF_SET(name) \
585 if (config->name) { \
587 ystr(config->name); \
595 if (config->
mode == M_HIDE)
637 ystr(
"workspace_buttons");
644 #define YSTR_IF_SET(name) \
646 if (config->colors.name) { \
648 ystr(config->colors.name); \
675 const unsigned char *payload;
681 y(get_buf, &payload, &length);
700 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, len, s);
708 memcpy(client->
events[event], s, len);
710 DLOG(
"client is now subscribed to:\n");
725 yajl_callbacks callbacks;
731 if (current->
fd != fd)
738 if (client == NULL) {
739 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
744 memset(&callbacks, 0,
sizeof(yajl_callbacks));
748 p = yajl_alloc(&callbacks, NULL, (
void*)client);
750 p = yajl_alloc(&callbacks, NULL, NULL, (
void*)client);
752 stat = yajl_parse(p, (
const unsigned char*)message, message_size);
753 if (stat != yajl_status_ok) {
755 err = yajl_get_error(p,
true, (
const unsigned char*)message,
757 ELOG(
"YAJL parse error: %s\n", err);
758 yajl_free_error(p, err);
760 const char *reply =
"{\"success\":false}";
761 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
766 const char *reply =
"{\"success\":true}";
767 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
774 handle_get_workspaces,
779 handle_get_bar_config,
794 int n = read(w->fd, buf,
sizeof(buf));
802 if (errno == EAGAIN || errno == EWOULDBLOCK)
813 if (current->
fd != w->fd)
828 DLOG(
"IPC: client disconnected\n");
836 if (n < strlen(I3_IPC_MAGIC)) {
837 DLOG(
"IPC: message too short, ignoring\n");
841 if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
842 DLOG(
"IPC: message does not start with the IPC magic\n");
846 uint8_t *message = (uint8_t*)buf;
848 DLOG(
"IPC: n = %d\n", n);
849 message += strlen(I3_IPC_MAGIC);
850 n -= strlen(I3_IPC_MAGIC);
853 uint32_t message_size;
854 memcpy(&message_size, (uint32_t*)message,
sizeof(uint32_t));
855 message +=
sizeof(uint32_t);
856 n -=
sizeof(uint32_t);
858 if (message_size > n) {
859 DLOG(
"IPC: Either the message size was wrong or the message was not read completely, dropping\n");
864 uint32_t message_type;
865 memcpy(&message_type, (uint32_t*)message,
sizeof(uint32_t));
866 message +=
sizeof(uint32_t);
867 n -=
sizeof(uint32_t);
869 if (message_type >= (
sizeof(handlers) /
sizeof(
handler_t)))
870 DLOG(
"Unhandled message type: %d\n", message_type);
873 h(w->fd, message, n, message_size, message_type);
876 message += message_size;
888 struct sockaddr_un peer;
889 socklen_t len =
sizeof(
struct sockaddr_un);
891 if ((client = accept(w->fd, (
struct sockaddr*)&peer, &len)) < 0) {
894 else perror(
"accept()");
899 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
901 set_nonblock(client);
903 struct ev_io *
package = scalloc(sizeof(struct ev_io));
905 ev_io_start(EV_A_ package);
907 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
926 DLOG(
"Creating IPC-socket at %s\n", resolved);
927 char *copy =
sstrdup(resolved);
928 const char *dir = dirname(copy);
936 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
942 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
944 struct sockaddr_un addr;
945 memset(&addr, 0,
sizeof(
struct sockaddr_un));
946 addr.sun_family = AF_LOCAL;
947 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
948 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0) {
954 set_nonblock(sockfd);
956 if (listen(sockfd, 5) < 0) {