* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
- * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
*
* ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
*
err(-1, "Could not set O_NONBLOCK");
}
-/*
- * Emulates mkdir -p (creates any missing folders)
- *
- */
-bool mkdirp(const char *path) {
- if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
- return true;
- if (errno != ENOENT) {
- ELOG("mkdir(%s) failed: %s\n", path, strerror(errno));
- return false;
- }
- char *copy = sstrdup(path);
- /* strip trailing slashes, if any */
- while (copy[strlen(copy) - 1] == '/')
- copy[strlen(copy) - 1] = '\0';
-
- char *sep = strrchr(copy, '/');
- if (sep == NULL) {
- FREE(copy);
- return false;
- }
- *sep = '\0';
- bool result = false;
- if (mkdirp(copy))
- result = mkdirp(path);
- free(copy);
-
- return result;
-}
-
/*
* Sends the specified event to all IPC clients which are currently connected
* and subscribed to this kind of event.
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");
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(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(array_open);
Match *match;
TAILQ_FOREACH(match, &(con->swallow_head), matches) {
+ /* We will generate a new restart_mode match specification after this
+ * loop, so skip this one. */
+ if (match->restart_mode)
+ continue;
y(map_open);
if (match->dock != -1) {
ystr("dock");
y(map_close);
}
+static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
+ if (TAILQ_EMPTY(&(config->bar_bindings)))
+ return;
+
+ ystr("bindings");
+ y(array_open);
+
+ struct Barbinding *current;
+ TAILQ_FOREACH(current, &(config->bar_bindings), bindings) {
+ y(map_open);
+
+ ystr("input_code");
+ y(integer, current->input_code);
+ ystr("command");
+ ystr(current->command);
+
+ y(map_close);
+ }
+
+ y(array_close);
+}
+
static void dump_bar_config(yajl_gen gen, Barconfig *config) {
y(map_open);
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);
- }
+ dump_bar_bindings(gen, config);
ystr("position");
if (config->position == P_BOTTOM)
YSTR_IF_SET(status_command);
YSTR_IF_SET(font);
+ if (config->separator_symbol) {
+ ystr("separator_symbol");
+ ystr(config->separator_symbol);
+ }
+
ystr("workspace_buttons");
y(bool, !config->hide_workspace_buttons);
YSTR_IF_SET(urgent_workspace_border);
YSTR_IF_SET(urgent_workspace_bg);
YSTR_IF_SET(urgent_workspace_text);
+ YSTR_IF_SET(binding_mode_border);
+ YSTR_IF_SET(binding_mode_bg);
+ YSTR_IF_SET(binding_mode_text);
y(map_close);
y(map_close);
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);
y(integer, PATCH_VERSION);
ystr("human_readable");
- ystr(I3_VERSION);
+ ystr(i3_version);
y(map_close);
}
/*
- * 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);
- setlocale(LC_NUMERIC, "");
}
/**
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, "");
+}