X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fipc.c;h=0f3dcd82b7d2b115310a5cbbf012942e6aa769e4;hb=92000942039fa99d7334ca5099b467b0d3d17792;hp=5232acf2779cdb8a406f9a6a42ca8577433fb3d3;hpb=dece12bf1857ac2384e2da8917f65f2dfe3f2b37;p=i3%2Fi3 diff --git a/src/ipc.c b/src/ipc.c index 5232acf2..0f3dcd82 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -10,6 +10,7 @@ * */ #include "all.h" +#include "yajl_utils.h" #include #include @@ -18,14 +19,9 @@ #include #include #include -#include char *current_socketpath = NULL; -/* Shorter names for all those yajl_gen_* functions */ -#define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__) -#define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str)) - TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients); /* @@ -54,8 +50,8 @@ static bool mkdirp(const char *path) { } char *copy = sstrdup(path); /* strip trailing slashes, if any */ - while (copy[strlen(copy)-1] == '/') - copy[strlen(copy)-1] = '\0'; + while (copy[strlen(copy) - 1] == '/') + copy[strlen(copy) - 1] = '\0'; char *sep = strrchr(copy, '/'); if (sep == NULL) { @@ -78,7 +74,7 @@ static bool mkdirp(const char *path) { */ void ipc_send_event(const char *event, uint32_t message_type, const char *payload) { ipc_client *current; - TAILQ_FOREACH(current, &all_clients, clients) { + TAILQ_FOREACH (current, &all_clients, clients) { /* see if this client is interested in this event */ bool interested = false; for (int i = 0; i < current->num_events; i++) { @@ -90,7 +86,7 @@ void ipc_send_event(const char *event, uint32_t message_type, const char *payloa if (!interested) continue; - ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t*)payload); + ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t *)payload); } } @@ -119,26 +115,26 @@ IPC_HANDLER(command) { /* To get a properly terminated buffer, we copy * message_size bytes out of the buffer */ char *command = scalloc(message_size + 1); - strncpy(command, (const char*)message, message_size); + strncpy(command, (const char *)message, message_size); LOG("IPC: received: *%s*\n", command); - struct CommandResult *command_output = parse_command((const char*)command); + yajl_gen gen = yajl_gen_alloc(NULL); + + CommandResult *result = parse_command((const char *)command, gen); free(command); - if (command_output->needs_tree_render) + if (result->needs_tree_render) tree_render(); + command_result_free(result); + const unsigned char *reply; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif - yajl_gen_get_buf(command_output->json_gen, &reply, &length); + ylength length; + yajl_gen_get_buf(gen, &reply, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND, - (const uint8_t*)reply); + (const uint8_t *)reply); - yajl_gen_free(command_output->json_gen); + yajl_gen_free(gen); } static void dump_rect(yajl_gen gen, const char *name, Rect r) { @@ -161,7 +157,30 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { y(integer, (long int)con); ystr("type"); - y(integer, con->type); + switch (con->type) { + case CT_ROOT: + ystr("root"); + break; + case CT_OUTPUT: + ystr("output"); + break; + case CT_CON: + ystr("con"); + break; + case CT_FLOATING_CON: + ystr("floating_con"); + break; + case CT_WORKSPACE: + ystr("workspace"); + break; + case CT_DOCKAREA: + ystr("dockarea"); + break; + default: + DLOG("About to dump unknown container type=%d. This is a bug.\n", con->type); + assert(false); + break; + } /* provided for backwards compatibility only. */ ystr("orientation"); @@ -170,7 +189,8 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { else { if (con_orientation(con) == HORIZ) ystr("horizontal"); - else ystr("vertical"); + else + ystr("vertical"); } ystr("scratchpad_state"); @@ -189,7 +209,8 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { ystr("percent"); if (con->percent == 0.0) y(null); - else y(double, con->percent); + else + y(double, con->percent); ystr("urgent"); y(bool, con->urgent); @@ -289,13 +310,41 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { ystr("window"); if (con->window) y(integer, con->window->id); - else y(null); + else + y(null); + + if (con->window && !inplace_restart) { + /* Window properties are useless to preserve when restarting because + * they will be queried again anyway. However, for i3-save-tree(1), + * they are very useful and save i3-save-tree dealing with X11. */ + ystr("window_properties"); + y(map_open); + +#define DUMP_PROPERTY(key, prop_name) \ + do { \ + if (con->window->prop_name != NULL) { \ + ystr(key); \ + ystr(con->window->prop_name); \ + } \ + } while (0) + + DUMP_PROPERTY("class", class_class); + DUMP_PROPERTY("instance", class_instance); + DUMP_PROPERTY("window_role", role); + + if (con->window->name != NULL) { + ystr("title"); + ystr(i3string_as_utf8(con->window->name)); + } + + y(map_close); + } ystr("nodes"); y(array_open); Con *node; if (con->type != CT_DOCKAREA || !inplace_restart) { - TAILQ_FOREACH(node, &(con->nodes_head), nodes) { + TAILQ_FOREACH (node, &(con->nodes_head), nodes) { dump_node(gen, node, inplace_restart); } } @@ -303,14 +352,14 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { ystr("floating_nodes"); y(array_open); - TAILQ_FOREACH(node, &(con->floating_head), floating_windows) { + TAILQ_FOREACH (node, &(con->floating_head), floating_windows) { dump_node(gen, node, inplace_restart); } y(array_close); ystr("focus"); y(array_open); - TAILQ_FOREACH(node, &(con->focus_head), focused) { + TAILQ_FOREACH (node, &(con->focus_head), focused) { y(integer, (long int)node); } y(array_close); @@ -337,17 +386,30 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { ystr("swallows"); y(array_open); Match *match; - TAILQ_FOREACH(match, &(con->swallow_head), matches) { + TAILQ_FOREACH (match, &(con->swallow_head), matches) { + y(map_open); if (match->dock != -1) { - y(map_open); ystr("dock"); y(integer, match->dock); ystr("insert_where"); y(integer, match->insert_where); - y(map_close); } - /* TODO: the other swallow keys */ +#define DUMP_REGEX(re_name) \ + do { \ + if (match->re_name != NULL) { \ + ystr(#re_name); \ + ystr(match->re_name->pattern); \ + } \ + } while (0) + + DUMP_REGEX(class); + DUMP_REGEX(instance); + DUMP_REGEX(window_role); + DUMP_REGEX(title); + +#undef DUMP_REGEX + y(map_close); } if (inplace_restart) { @@ -362,60 +424,186 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { } y(array_close); + if (inplace_restart && con->window != NULL) { + ystr("depth"); + y(integer, con->depth); + } + + y(map_close); +} + +static void dump_bar_config(yajl_gen gen, Barconfig *config) { + y(map_open); + + ystr("id"); + ystr(config->id); + + if (config->num_outputs > 0) { + ystr("outputs"); + y(array_open); + for (int c = 0; c < config->num_outputs; c++) + ystr(config->outputs[c]); + y(array_close); + } + +#define YSTR_IF_SET(name) \ + do { \ + if (config->name) { \ + ystr(#name); \ + ystr(config->name); \ + } \ + } while (0) + + YSTR_IF_SET(tray_output); + YSTR_IF_SET(socket_path); + + ystr("mode"); + switch (config->mode) { + case M_HIDE: + ystr("hide"); + break; + case M_INVISIBLE: + ystr("invisible"); + break; + case M_DOCK: + default: + ystr("dock"); + break; + } + + ystr("hidden_state"); + switch (config->hidden_state) { + case S_SHOW: + ystr("show"); + break; + case S_HIDE: + default: + ystr("hide"); + break; + } + + ystr("modifier"); + switch (config->modifier) { + case M_CONTROL: + ystr("ctrl"); + break; + case M_SHIFT: + ystr("shift"); + break; + case M_MOD1: + ystr("Mod1"); + break; + case M_MOD2: + ystr("Mod2"); + break; + case M_MOD3: + ystr("Mod3"); + break; + /* + case M_MOD4: + ystr("Mod4"); + break; + */ + case M_MOD5: + ystr("Mod5"); + break; + default: + ystr("Mod4"); + break; + } + + ystr("position"); + if (config->position == P_BOTTOM) + ystr("bottom"); + else + ystr("top"); + + YSTR_IF_SET(status_command); + YSTR_IF_SET(font); + + ystr("workspace_buttons"); + y(bool, !config->hide_workspace_buttons); + + ystr("strip_workspace_numbers"); + y(bool, config->strip_workspace_numbers); + + ystr("binding_mode_indicator"); + y(bool, !config->hide_binding_mode_indicator); + + ystr("verbose"); + y(bool, config->verbose); + +#undef YSTR_IF_SET +#define YSTR_IF_SET(name) \ + do { \ + if (config->colors.name) { \ + ystr(#name); \ + ystr(config->colors.name); \ + } \ + } while (0) + + ystr("colors"); + y(map_open); + YSTR_IF_SET(background); + YSTR_IF_SET(statusline); + YSTR_IF_SET(separator); + YSTR_IF_SET(focused_workspace_border); + YSTR_IF_SET(focused_workspace_bg); + YSTR_IF_SET(focused_workspace_text); + YSTR_IF_SET(active_workspace_border); + YSTR_IF_SET(active_workspace_bg); + YSTR_IF_SET(active_workspace_text); + YSTR_IF_SET(inactive_workspace_border); + YSTR_IF_SET(inactive_workspace_bg); + YSTR_IF_SET(inactive_workspace_text); + YSTR_IF_SET(urgent_workspace_border); + YSTR_IF_SET(urgent_workspace_bg); + YSTR_IF_SET(urgent_workspace_text); + y(map_close); + y(map_close); +#undef YSTR_IF_SET } IPC_HANDLER(tree) { setlocale(LC_NUMERIC, "C"); -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); dump_node(gen, croot, false); setlocale(LC_NUMERIC, ""); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload); y(free); } - /* * Formats the reply message for a GET_WORKSPACES request and sends it to the * client * */ IPC_HANDLER(get_workspaces) { -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); y(array_open); Con *focused_ws = con_get_workspace(focused); Con *output; - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { + TAILQ_FOREACH (output, &(croot->nodes_head), nodes) { if (con_is_internal(output)) continue; Con *ws; - TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { + TAILQ_FOREACH (ws, &(output_get_content(output)->nodes_head), nodes) { assert(ws->type == CT_WORKSPACE); y(map_open); ystr("num"); if (ws->num == -1) y(null); - else y(integer, ws->num); + else + y(integer, ws->num); ystr("name"); ystr(ws->name); @@ -451,11 +639,7 @@ IPC_HANDLER(get_workspaces) { y(array_close); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload); @@ -468,15 +652,11 @@ IPC_HANDLER(get_workspaces) { * */ IPC_HANDLER(get_outputs) { -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); y(array_open); Output *output; - TAILQ_FOREACH(output, &outputs, outputs) { + TAILQ_FOREACH (output, &outputs, outputs) { y(map_open); ystr("name"); @@ -504,7 +684,8 @@ IPC_HANDLER(get_outputs) { Con *ws = NULL; if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT))) ystr(ws->name); - else y(null); + else + y(null); y(map_close); } @@ -512,11 +693,7 @@ IPC_HANDLER(get_outputs) { y(array_close); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload); @@ -529,26 +706,18 @@ IPC_HANDLER(get_outputs) { * */ IPC_HANDLER(get_marks) { -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); y(array_open); Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) + TAILQ_FOREACH (con, &all_cons, all_cons) if (con->mark != NULL) ystr(con->mark); y(array_close); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload); @@ -560,11 +729,7 @@ IPC_HANDLER(get_marks) { * */ IPC_HANDLER(get_version) { -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); y(map_open); ystr("major"); @@ -582,11 +747,7 @@ IPC_HANDLER(get_version) { y(map_close); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload); @@ -599,27 +760,19 @@ IPC_HANDLER(get_version) { * */ IPC_HANDLER(get_bar_config) { -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif + yajl_gen gen = ygenalloc(); /* If no ID was passed, we return a JSON array with all IDs */ if (message_size == 0) { y(array_open); Barconfig *current; - TAILQ_FOREACH(current, &barconfigs, configs) { + TAILQ_FOREACH (current, &barconfigs, configs) { ystr(current->id); } y(array_close); const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); @@ -630,10 +783,10 @@ IPC_HANDLER(get_bar_config) { /* To get a properly terminated buffer, we copy * message_size bytes out of the buffer */ char *bar_id = scalloc(message_size + 1); - strncpy(bar_id, (const char*)message, message_size); + strncpy(bar_id, (const char *)message, message_size); LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id); Barconfig *current, *config = NULL; - TAILQ_FOREACH(current, &barconfigs, configs) { + TAILQ_FOREACH (current, &barconfigs, configs) { if (strcmp(current->id, bar_id) != 0) continue; @@ -641,123 +794,21 @@ IPC_HANDLER(get_bar_config) { break; } - y(map_open); - if (!config) { /* If we did not find a config for the given ID, the reply will contain * a null 'id' field. */ + y(map_open); + ystr("id"); y(null); - } else { - ystr("id"); - ystr(config->id); - - if (config->num_outputs > 0) { - ystr("outputs"); - y(array_open); - for (int c = 0; c < config->num_outputs; c++) - ystr(config->outputs[c]); - y(array_close); - } - -#define YSTR_IF_SET(name) \ - do { \ - if (config->name) { \ - ystr( # name); \ - ystr(config->name); \ - } \ - } while (0) - - YSTR_IF_SET(tray_output); - YSTR_IF_SET(socket_path); - - ystr("mode"); - if (config->mode == M_HIDE) - ystr("hide"); - else ystr("dock"); - - ystr("modifier"); - switch (config->modifier) { - case M_CONTROL: - ystr("ctrl"); - break; - case M_SHIFT: - ystr("shift"); - break; - case M_MOD1: - ystr("Mod1"); - break; - case M_MOD2: - ystr("Mod2"); - break; - case M_MOD3: - ystr("Mod3"); - break; - /* - case M_MOD4: - ystr("Mod4"); - break; - */ - case M_MOD5: - ystr("Mod5"); - break; - default: - ystr("Mod4"); - break; - } - ystr("position"); - if (config->position == P_BOTTOM) - ystr("bottom"); - else ystr("top"); - - YSTR_IF_SET(status_command); - YSTR_IF_SET(font); - - ystr("workspace_buttons"); - y(bool, !config->hide_workspace_buttons); - - ystr("verbose"); - y(bool, config->verbose); - -#undef YSTR_IF_SET -#define YSTR_IF_SET(name) \ - do { \ - if (config->colors.name) { \ - ystr( # name); \ - ystr(config->colors.name); \ - } \ - } while (0) - - ystr("colors"); - y(map_open); - YSTR_IF_SET(background); - YSTR_IF_SET(statusline); - YSTR_IF_SET(focused_workspace_border); - YSTR_IF_SET(focused_workspace_bg); - YSTR_IF_SET(focused_workspace_text); - YSTR_IF_SET(active_workspace_border); - YSTR_IF_SET(active_workspace_bg); - YSTR_IF_SET(active_workspace_text); - YSTR_IF_SET(inactive_workspace_border); - YSTR_IF_SET(inactive_workspace_bg); - YSTR_IF_SET(inactive_workspace_text); - YSTR_IF_SET(urgent_workspace_border); - YSTR_IF_SET(urgent_workspace_bg); - YSTR_IF_SET(urgent_workspace_text); y(map_close); - -#undef YSTR_IF_SET + } else { + dump_bar_config(gen, config); } - y(map_close); - const unsigned char *payload; -#if YAJL_MAJOR >= 2 - size_t length; -#else - unsigned int length; -#endif + ylength length; y(get_buf, &payload, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); @@ -768,23 +819,18 @@ IPC_HANDLER(get_bar_config) { * Callback for the YAJL parser (will be called when a string is parsed). * */ -#if YAJL_MAJOR < 2 static int add_subscription(void *extra, const unsigned char *s, - unsigned int len) { -#else -static int add_subscription(void *extra, const unsigned char *s, - size_t len) { -#endif + ylength len) { ipc_client *client = extra; DLOG("should add subscription to extra %p, sub %.*s\n", client, (int)len, s); int event = client->num_events; client->num_events++; - client->events = realloc(client->events, client->num_events * sizeof(char*)); + client->events = realloc(client->events, client->num_events * sizeof(char *)); /* We copy the string because it is not null-terminated and strndup() * is missing on some BSD systems */ - client->events[event] = scalloc(len+1); + client->events[event] = scalloc(len + 1); memcpy(client->events[event], s, len); DLOG("client is now subscribed to:\n"); @@ -802,12 +848,11 @@ static int add_subscription(void *extra, const unsigned char *s, */ IPC_HANDLER(subscribe) { yajl_handle p; - yajl_callbacks callbacks; yajl_status stat; ipc_client *current, *client = NULL; /* Search the ipc_client structure for this connection */ - TAILQ_FOREACH(current, &all_clients, clients) { + TAILQ_FOREACH (current, &all_clients, clients) { if (current->fd != fd) continue; @@ -821,30 +866,27 @@ IPC_HANDLER(subscribe) { } /* Setup the JSON parser */ - memset(&callbacks, 0, sizeof(yajl_callbacks)); - callbacks.yajl_string = add_subscription; - -#if YAJL_MAJOR >= 2 - p = yajl_alloc(&callbacks, NULL, (void*)client); -#else - p = yajl_alloc(&callbacks, NULL, NULL, (void*)client); -#endif - stat = yajl_parse(p, (const unsigned char*)message, message_size); + static yajl_callbacks callbacks = { + .yajl_string = add_subscription, + }; + + p = yalloc(&callbacks, (void *)client); + stat = yajl_parse(p, (const unsigned char *)message, message_size); if (stat != yajl_status_ok) { unsigned char *err; - err = yajl_get_error(p, true, (const unsigned char*)message, + err = yajl_get_error(p, true, (const unsigned char *)message, message_size); ELOG("YAJL parse error: %s\n", err); yajl_free_error(p, err); const char *reply = "{\"success\":false}"; - ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply); + ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply); yajl_free(p); return; } yajl_free(p); const char *reply = "{\"success\":true}"; - ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply); + ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply); } /* The index of each callback function corresponds to the numeric @@ -871,18 +913,18 @@ handler_t handlers[8] = { * */ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { - char buf[2048]; - int n = read(w->fd, buf, sizeof(buf)); - - /* On error or an empty message, we close the connection */ - if (n <= 0) { -#if 0 - /* FIXME: I get these when closing a client socket, - * therefore we just treat them as an error. Is this - * correct? */ - if (errno == EAGAIN || errno == EWOULDBLOCK) - return; -#endif + uint32_t message_type; + uint32_t message_length; + uint8_t *message = NULL; + + int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message); + /* EOF or other error */ + if (ret < 0) { + /* Was this a spurious read? See ev(3) */ + if (ret == -1 && errno == EAGAIN) { + FREE(message); + return; + } /* If not, there was some kind of error. We don’t bother * and close the connection */ @@ -890,7 +932,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { /* Delete the client from the list of clients */ ipc_client *current; - TAILQ_FOREACH(current, &all_clients, clients) { + TAILQ_FOREACH (current, &all_clients, clients) { if (current->fd != w->fd) continue; @@ -905,57 +947,20 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { ev_io_stop(EV_A_ w); free(w); + FREE(message); DLOG("IPC: client disconnected\n"); return; } - /* Terminate the message correctly */ - buf[n] = '\0'; - - /* Check if the message starts with the i3 IPC magic code */ - if (n < strlen(I3_IPC_MAGIC)) { - DLOG("IPC: message too short, ignoring\n"); - return; - } - - if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { - DLOG("IPC: message does not start with the IPC magic\n"); - return; + if (message_type >= (sizeof(handlers) / sizeof(handler_t))) + DLOG("Unhandled message type: %d\n", message_type); + else { + handler_t h = handlers[message_type]; + h(w->fd, message, 0, message_length, message_type); } - uint8_t *message = (uint8_t*)buf; - while (n > 0) { - DLOG("IPC: n = %d\n", n); - message += strlen(I3_IPC_MAGIC); - n -= strlen(I3_IPC_MAGIC); - - /* The next 32 bit after the magic are the message size */ - uint32_t message_size; - memcpy(&message_size, (uint32_t*)message, sizeof(uint32_t)); - message += sizeof(uint32_t); - n -= sizeof(uint32_t); - - if (message_size > n) { - DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n"); - return; - } - - /* The last 32 bits of the header are the message type */ - uint32_t message_type; - memcpy(&message_type, (uint32_t*)message, sizeof(uint32_t)); - message += sizeof(uint32_t); - n -= sizeof(uint32_t); - - if (message_type >= (sizeof(handlers) / sizeof(handler_t))) - DLOG("Unhandled message type: %d\n", message_type); - else { - handler_t h = handlers[message_type]; - h(w->fd, message, n, message_size, message_type); - } - n -= message_size; - message += message_size; - } + FREE(message); } /* @@ -969,10 +974,11 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) { struct sockaddr_un peer; socklen_t len = sizeof(struct sockaddr_un); int client; - if ((client = accept(w->fd, (struct sockaddr*)&peer, &len)) < 0) { + if ((client = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) { if (errno == EINTR) return; - else perror("accept()"); + else + perror("accept()"); return; } @@ -1026,7 +1032,7 @@ int ipc_create_socket(const char *filename) { memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_LOCAL; strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1); - if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) { + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { perror("bind()"); free(resolved); return -1; @@ -1043,3 +1049,86 @@ int ipc_create_socket(const char *filename) { current_socketpath = resolved; return sockfd; } + +/* + * For the workspace "focus" event we send, along the usual "change" field, + * also the current and previous workspace, in "current" and "old" + * respectively. + */ +void ipc_send_workspace_focus_event(Con *current, Con *old) { + setlocale(LC_NUMERIC, "C"); + yajl_gen gen = ygenalloc(); + + y(map_open); + + ystr("change"); + ystr("focus"); + + ystr("current"); + dump_node(gen, current, false); + + ystr("old"); + if (old == NULL) + y(null); + else + dump_node(gen, old, false); + + y(map_close); + + const unsigned char *payload; + ylength length; + y(get_buf, &payload, &length); + + ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); + y(free); + setlocale(LC_NUMERIC, ""); +} + +/** + * For the window events we send, along the usual "change" field, + * also the window container, in "container". + */ +void ipc_send_window_event(const char *property, Con *con) { + DLOG("Issue IPC window %s event (con = %p, window = 0x%08x)\n", + property, con, (con->window ? con->window->id : XCB_WINDOW_NONE)); + + setlocale(LC_NUMERIC, "C"); + yajl_gen gen = ygenalloc(); + + y(map_open); + + ystr("change"); + ystr(property); + + ystr("container"); + dump_node(gen, con, false); + + y(map_close); + + const unsigned char *payload; + ylength length; + y(get_buf, &payload, &length); + + ipc_send_event("window", I3_IPC_EVENT_WINDOW, (const char *)payload); + y(free); + setlocale(LC_NUMERIC, ""); +} + +/** + * For the barconfig update events, we send the serialized barconfig. + */ +void ipc_send_barconfig_update_event(Barconfig *barconfig) { + DLOG("Issue barconfig_update event for id = %s\n", barconfig->id); + setlocale(LC_NUMERIC, "C"); + yajl_gen gen = ygenalloc(); + + dump_bar_config(gen, barconfig); + + const unsigned char *payload; + ylength length; + y(get_buf, &payload, &length); + + ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (const char *)payload); + y(free); + setlocale(LC_NUMERIC, ""); +}