* Emulates mkdir -p (creates any missing folders)
*
*/
-static bool mkdirp(const char *path) {
+bool mkdirp(const char *path) {
if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
return true;
if (errno != ENOENT) {
}
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) {
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);
}
}
/* 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;
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);
+ (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) {
y(map_close);
}
+static void dump_binding(yajl_gen gen, Binding *bind) {
+ y(map_open);
+ ystr("input_code");
+ y(integer, bind->keycode);
+
+ ystr("input_type");
+ ystr((const char *)(bind->input_type == B_KEYBOARD ? "keyboard" : "mouse"));
+
+ ystr("symbol");
+ if (bind->symbol == NULL)
+ y(null);
+ else
+ ystr(bind->symbol);
+
+ ystr("command");
+ ystr(bind->command);
+
+ ystr("mods");
+ y(array_open);
+ for (int i = 0; i < 8; i++) {
+ if (bind->mods & (1 << i)) {
+ switch (1 << i) {
+ case XCB_MOD_MASK_SHIFT:
+ ystr("shift");
+ break;
+ case XCB_MOD_MASK_LOCK:
+ ystr("lock");
+ break;
+ case XCB_MOD_MASK_CONTROL:
+ ystr("ctrl");
+ break;
+ case XCB_MOD_MASK_1:
+ ystr("Mod1");
+ break;
+ case XCB_MOD_MASK_2:
+ ystr("Mod2");
+ break;
+ case XCB_MOD_MASK_3:
+ ystr("Mod3");
+ break;
+ case XCB_MOD_MASK_4:
+ ystr("Mod4");
+ break;
+ case XCB_MOD_MASK_5:
+ ystr("Mod5");
+ break;
+ }
+ }
+ }
+ y(array_close);
+
+ y(map_close);
+}
+
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
y(map_open);
ystr("id");
else {
if (con_orientation(con) == HORIZ)
ystr("horizontal");
- else ystr("vertical");
+ else
+ ystr("vertical");
}
ystr("scratchpad_state");
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);
y(integer, con->current_border_width);
dump_rect(gen, "rect", con->rect);
+ dump_rect(gen, "deco_rect", con->deco_rect);
dump_rect(gen, "window_rect", con->window_rect);
dump_rect(gen, "geometry", con->geometry);
ystr("name");
if (con->window && con->window->name)
ystr(i3string_as_utf8(con->window->name));
- else
+ else if (con->name != NULL)
ystr(con->name);
+ else
+ y(null);
if (con->type == CT_WORKSPACE) {
ystr("num");
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
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)
+#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);
ystr(i3string_as_utf8(con->window->name));
}
+ ystr("transient_for");
+ if (con->window->transient_for == XCB_NONE)
+ y(null);
+ else
+ y(integer, con->window->transient_for);
+
y(map_close);
}
y(integer, match->insert_where);
}
-#define DUMP_REGEX(re_name) do { \
- if (match->re_name != NULL) { \
- ystr(# re_name); \
- ystr(match->re_name->pattern); \
- } \
-} while (0)
+#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);
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;
+ }
+
+ if (config->wheel_up_cmd) {
+ ystr("wheel_up_cmd");
+ ystr(config->wheel_up_cmd);
+ }
+
+ if (config->wheel_down_cmd) {
+ ystr("wheel_down_cmd");
+ ystr(config->wheel_down_cmd);
+ }
+
+ 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();
y(free);
}
-
/*
* Formats the reply message for a GET_WORKSPACES request and sends it to the
* client
y(map_open);
ystr("num");
- if (ws->num == -1)
- y(null);
- else y(integer, ws->num);
+ y(integer, ws->num);
ystr("name");
ystr(ws->name);
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);
}
Con *con;
TAILQ_FOREACH(con, &all_cons, all_cons)
- if (con->mark != NULL)
- ystr(con->mark);
+ if (con->mark != NULL)
+ ystr(con->mark);
y(array_close);
/* 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) {
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);
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");
.yajl_string = add_subscription,
};
- p = yalloc(&callbacks, (void*)client);
- stat = yajl_parse(p, (const unsigned char*)message, message_size);
+ 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
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 */
ev_io_stop(EV_A_ w);
free(w);
+ FREE(message);
DLOG("IPC: client disconnected\n");
return;
handler_t h = handlers[message_type];
h(w->fd, message, 0, message_length, message_type);
}
+
+ FREE(message);
}
/*
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;
}
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;
}
/*
- * For the workspace "focus" event we send, along the usual "change" field,
- * also the current and previous workspace, in "current" and "old"
- * respectively.
+ * Generates a json workspace event. Returns a dynamically allocated yajl
+ * generator. Free with yajl_gen_free().
*/
-void ipc_send_workspace_focus_event(Con *current, Con *old) {
+yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) {
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
- ystr("focus");
+ ystr(change);
ystr("current");
- dump_node(gen, current, false);
+ if (current == NULL)
+ y(null);
+ else
+ dump_node(gen, current, false);
ystr("old");
if (old == NULL)
y(map_close);
+ setlocale(LC_NUMERIC, "");
+
+ return gen;
+}
+
+/*
+ * For the workspace events we send, along with the usual "change" field, also
+ * the workspace container in "current". For focus events, we send the
+ * previously focused workspace in "old".
+ */
+void ipc_send_workspace_event(const char *change, Con *current, Con *old) {
+ yajl_gen gen = ipc_marshal_workspace_event(change, current, old);
+
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
+
+ y(free);
+}
+
+/**
+ * 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, "");
+}
+
+/*
+ * For the binding events, we send the serialized binding struct.
+ */
+void ipc_send_binding_event(const char *event_type, Binding *bind) {
+ DLOG("Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->symbol, bind->keycode);
+
+ setlocale(LC_NUMERIC, "C");
+
+ yajl_gen gen = ygenalloc();
+
+ y(map_open);
+
+ ystr("change");
+ ystr(event_type);
+
+ ystr("binding");
+ dump_binding(gen, bind);
+
+ y(map_close);
+
+ const unsigned char *payload;
+ ylength length;
+ y(get_buf, &payload, &length);
+
+ ipc_send_event("binding", I3_IPC_EVENT_BINDING, (const char *)payload);
+
y(free);
setlocale(LC_NUMERIC, "");
}