X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fipc.c;h=0d2c92b87ecfe9fec062fa7804dcb862bc12e29d;hb=617afc67a25c9bb7bf91a7659319e07fbe32d758;hp=4247ca5c88fbb8db4f031ee7a6e81981ee8f1e61;hpb=b8ba545733f2c171d018901f563f1d9625d44804;p=i3%2Fi3 diff --git a/src/ipc.c b/src/ipc.c index 4247ca5c..0d2c92b8 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -117,20 +117,24 @@ IPC_HANDLER(command) { char *command = scalloc(message_size + 1); 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; ylength length; - yajl_gen_get_buf(command_output->json_gen, &reply, &length); + yajl_gen_get_buf(gen, &reply, &length); ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND, (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) { @@ -153,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"); @@ -283,6 +310,32 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { y(integer, con->window->id); 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; @@ -330,16 +383,28 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { y(array_open); Match *match; 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,6 +427,138 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { 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"); yajl_gen gen = ygenalloc(); @@ -590,141 +787,19 @@ 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"); - 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("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); - -#undef YSTR_IF_SET + } else { + dump_bar_config(gen, config); } - y(map_close); - const unsigned char *payload; ylength length; y(get_buf, &payload, &length); @@ -766,7 +841,6 @@ 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; @@ -785,8 +859,9 @@ IPC_HANDLER(subscribe) { } /* Setup the JSON parser */ - memset(&callbacks, 0, sizeof(yajl_callbacks)); - callbacks.yajl_string = add_subscription; + static yajl_callbacks callbacks = { + .yajl_string = add_subscription, + }; p = yalloc(&callbacks, (void*)client); stat = yajl_parse(p, (const unsigned char*)message, message_size); @@ -833,14 +908,16 @@ handler_t handlers[8] = { static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { uint32_t message_type; uint32_t message_length; - uint8_t *message; + 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) + if (ret == -1 && errno == EAGAIN) { + FREE(message); return; + } /* If not, there was some kind of error. We don’t bother * and close the connection */ @@ -863,6 +940,7 @@ 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; @@ -874,6 +952,8 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { handler_t h = handlers[message_type]; h(w->fd, message, 0, message_length, message_type); } + + FREE(message); } /* @@ -995,3 +1075,52 @@ void ipc_send_workspace_focus_event(Con *current, Con *old) { 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, ""); +}